PillButton

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

Variants

Custom colors

Style each face independently with primaryClassName and secondaryClassName.

Doom mode

Click to arm

Install

Add the item with the shadcn CLI.

npx shadcn@latest add @evilbuttons/pill-button

Usage

[]txt
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:

[]txt
<PillButton
  primaryLabel="Mute"
  secondaryLabel="Live"
  isOpen={isLive}
  onOpenChange={setIsLive}
/>

Props

PropTypeDefaultDescription
primaryLabelstring-Label shown on the closed face.
secondaryLabelstring-Label shown on the open face.
primaryClassNamestring-Classes applied to the primary face.
secondaryClassNamestring-Classes applied to the secondary face.
isOpenboolean-Controlled open state.
defaultOpenbooleanfalseInitial open state when uncontrolled.
onOpenChange(open: boolean) => void-Called when the toggle state changes.
classNamestring-Extra classes on the outer pill container.
ariaLabelstring | ((isOpen: boolean) => string)label of active faceAccessible name for the toggle.

Notes

  • The outer element is a role="button" toggle with aria-expanded and keyboard support for Enter and Space.
  • PillFace and RollingLabel are 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.