CaptchaButton guards its action behind a tiny, absurd captcha. Clicking the trigger pops a panel asking you to "select all the demons" (and other rotating prompts) from a 3x3 grid of emoji tiles. The real action only fires once you select exactly the evil tiles. Get it wrong and the grid reshuffles with a fresh taunt.
Preview
CaptchaButton
Click, then prove you're evil
Install
Add the item with the shadcn CLI.
npx shadcn@latest add @evilbuttons/captcha-buttonUsage
import { CaptchaButton } from "@/components/evil-buttons/captcha-button";
export function ButtonDemo() {
return (
<CaptchaButton
successLabel="Access granted"
onConfirm={() => launchTheMissiles()}
>
Deploy Doom
</CaptchaButton>
);
}Props
The component spreads any <button> HTML attributes except onClick.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Trigger label. Falls back to label when omitted. |
label | React.ReactNode | "Do something evil" | Trigger label used when no children are provided. |
onConfirm | () => void | - | Fired once the captcha is passed. |
successLabel | React.ReactNode | "Access granted" | Label flashed briefly after passing. |
resetAfter | number | 1600 | Milliseconds to stay in the success state before resetting to idle. Set to 0 to stay. |
className | string | - | Extra classes passed to the trigger. |
Notes
- Each round randomly fills the grid with 2-4 evil tiles mixed with innocent ones; passing requires selecting exactly the evil set.
- The panel dismisses on outside click or Escape, and exposes
data-state(idle|open|success) for styling. - Animations (panel pop-in, tile tap, shake on a wrong answer) are skipped when the user prefers reduced motion.
- Emoji are rendered with Twemoji so the tiles look identical across every OS and browser.
Registry
The registry item includes components/evil-buttons/captcha-button.tsx, installs clsx, tailwind-merge, and motion, and pulls in the @ncdai/twemoji registry item for consistent emoji rendering.