PillButton is a compact two-state pill toggle. Click to spring between a primary and secondary face, each with its own label and styling. Hovering either face runs a rolling label animation through a soft vertical mask.
Preview
PillButton
Click to toggle
Off
On
Variants
Custom colors
Style each face independently with primaryClassName and secondaryClassName.
Doom mode
Click to arm
Safe
Doom
Install
Add the item with the shadcn CLI.
npx shadcn@latest add @evilbuttons/pill-buttonUsage
import { PillButton } from "@/components/evil-buttons/pill-button";
export function ButtonDemo() {
return (
<PillButton
primaryLabel="Off"
secondaryLabel="On"
primaryClassName="bg-neutral-950 text-neutral-200"
secondaryClassName="bg-primary text-primary-foreground"
onOpenChange={(open) => console.log("open:", open)}
/>
);
}Controlled usage:
<PillButton
primaryLabel="Mute"
secondaryLabel="Live"
isOpen={isLive}
onOpenChange={setIsLive}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
primaryLabel | string | - | Label shown on the closed face. |
secondaryLabel | string | - | Label shown on the open face. |
primaryClassName | string | - | Classes applied to the primary face. |
secondaryClassName | string | - | Classes applied to the secondary face. |
isOpen | boolean | - | Controlled open state. |
defaultOpen | boolean | false | Initial open state when uncontrolled. |
onOpenChange | (open: boolean) => void | - | Called when the toggle state changes. |
className | string | - | Extra classes on the outer pill container. |
ariaLabel | string | ((isOpen: boolean) => string) | label of active face | Accessible name for the toggle. |
Notes
- The outer element is a
role="button"toggle witharia-expandedand keyboard support for Enter and Space. PillFaceandRollingLabelare also exported if you want to compose the rolling label effect elsewhere.- The slide transition uses a spring; the hover label roll uses a eased vertical shift.
Registry
The registry item includes components/evil-buttons/pill-button.tsx and installs motion, clsx, and tailwind-merge as dependencies. The component imports cn from @/lib/utils.