Quack Button
A button with a full motion cycle: an idle animation while it waits, magnetic pull, a squash on press, and animated loading, success and error states.
ActionsClient componentclass-variance-authority@radix-ui/react-slotlucide-react
Preview
Installation
The CLI writes the source into your project and pulls in whatever it depends on.
$
pnpm dlx shadcn@latest add @duck/quack-buttonPulls in @duck/theme, @duck/duck-spinner, @duck/use-holo-pointer. Already installed items are skipped.
Usage
import { QuackButton } from "@/components/ui/quack-button"The file lands in components/ui/quack-button.tsx and belongs to you from that point on. Edit it in place rather than wrapping it.
Props
Everything not listed here is forwarded to the underlying element.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "primary" | "holo" | "outline" | "ghost" | "danger" | "primary" | Visual weight. Use holo for at most one button per screen. |
| size | "sm" | "default" | "lg" | "icon" | "default" | Control height and padding. |
| idle | "none" | "breathe" | "sheen" | "pulse" | "float" | "none" | Animation played while the button rests. One idle button per screen keeps the page calm. |
| magnetic | number | 0 | Maximum pull toward the pointer in px. 0 turns magnetism off. |
| ripple | boolean | true | Water ripple from the exact press point. |
| state | "idle" | "loading" | "success" | "error" | "idle" | Drives the transition. Loading also sets aria-busy and disables the button. |
| loadingLabel | string | - | Replaces the label while loading. |
| successLabel | string | - | Replaces the label on success. |
| errorLabel | string | - | Replaces the label on error. |
| asChild | boolean | false | Render the child element instead of a button, for links. |
Rules
What keeps this component from turning into noise.
- One idle animation per screen. Two competing loops read as a broken page.
- Keep the label stable between idle and loading unless the wait is long enough to explain.
- State is controlled. Reset it to idle yourself once the work finishes.
