Duck Cta Band
The closing ask: one headline, one button, and an optional email row that is a plain form — a URL or a server function, and no client code either way.
Preview
Install the theme, keep your components.
Every shadcn component already in the project inherits the tokens. Nothing to migrate.
MIT. No runtime dependency.
Installation
One command writes the section and every component it renders.
pnpm dlx shadcn@latest add @duck/duck-cta-bandThe block lands in components/blocks/duck-cta-band.tsx. It builds on sticker-card, holo-button, glow-input and hud-label, which the CLI installs alongside it. Already installed items are skipped.
Usage
import { DuckCtaBand } from "@/components/blocks/duck-cta-band"A block is a starting point, not a widget. The props exist so the example renders with real content — once the file is in your project, hard-code what never changes and delete the rest.
Props
Everything not listed here is forwarded to the root element.
| Prop | Type | Default | Description |
|---|---|---|---|
| eyebrow | React.ReactNode | - | HUD line above the headline. |
| title | React.ReactNode | - | The ask. One sentence. |
| description | React.ReactNode | - | The qualifier under it. |
| primaryAction | { label: string; href: string } | - | The button. It renders lime inside a holo band and holo inside a solid one, so the band carries exactly one iridescent element. |
| secondaryAction | { label: string; href: string } | - | Outline button beside it. |
| capture | DuckCtaBandCapture | - | action, method, name, type, placeholder, label, buttonLabel. action takes a URL string or a server function, so the same block posts to an endpoint on Vite and to a server action on Next. |
| note | React.ReactNode | - | Small print under the actions — "no card", "unsubscribe in one click". |
| variant | "holo" | "solid" | "holo" | The iridescent ring on the band, or a quiet card that gives the holo to its button instead. |
| align | "center" | "split" | "center" | Stacked and centred, or headline left and actions right once the container is wide enough. |
Rules
What keeps this section from turning into noise.
- The holo rule is per viewport, not per page. A band at the bottom may take the iridescent edge the hero already spent, because by then the hero is off screen.
- Never holo on both the band and its button. The block enforces it by flipping the primary action to lime inside a holo band.
- capture is a plain form and stays one. It has no state, no client code and no success message — a submitted form navigates or a server action re-renders, and both are the framework's job.
- The capture label wraps its input rather than pointing at an id, so two bands on one page cannot ship a duplicate id.
