Skip to content
WANCRAFT

A.124Buttons & Controls

Keycap Button

A mechanical keycap with a real skirt and dished top that travels down on a short spring, bottoms out and clacks.

NewReactMotionCSSTailwindintermediate

Overview

Keycap Button is a button built like a keycap. A sloped skirt and an inset top surface move together: on press the cap travels down on a near-critically-damped spring and bottoms out without overshoot, the contact shadow on the plate tightens, and an optional clack flashes a thin accent ring and a soft highlight. On release it springs back with your own spring. Legends can be text or an inline glyph, with an optional mono sub-legend, placed centred, top-left or bottom-left. Choose a tall cherry-style profile or a flat low-profile chiclet, a bone, carbon, accent or auto colourway, and any width in keyboard units. It is a real <button> — Enter and Space play the same press — and it becomes a latching key with aria-pressed and a status LED when you pass pressed or toggle.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/keycap-button.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/keycap-button.json

Method 02 · Copy and paste

  1. 1. Install the dependencies below.
  2. 2. Copy the source from the Code tab into components/ui/keycap-button.tsx.
  3. 3. Import it and adjust props.
npm install motion
Dependencies
motion
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { KeycapButton } from "@/components/ui/keycap-button";

export function KeycapButtonExample() {
  return (
    <KeycapButton
      legendPosition="top-left"
      onClick={() => console.log("pressed")}
    >
      K
    </KeycapButton>
  );
}

03Props

PropTypeDefaultDescription
childrenReactNode—Main legend: text or an inline SVG glyph.
subLegendReactNode—Small mono secondary legend under the main one.
labelstring—Accessible name; defaults to a string legend. Required for glyph-only legends.
legendPosition"center" | "top-left" | "bottom-left""center"Where the legends sit on the top surface.
unitsnumber1Width in keyboard units (1.25 for modifiers, 2.25 for shift, 6.25 for a spacebar).
unitSizenumber56Size of one unit (and the key height) in px.
profile"cherry" | "flat""cherry"Sculpted cap with a tall skirt and dish, or a flat low-profile chiclet.
theme"auto" | "carbon" | "bone" | "accent""auto"Colourway. auto is bone in light mode and carbon in dark mode.
accentstring"#FF7448"Accent colourway, latch LED, clack flash and focus ring.
travelnumber4Key travel in px before it bottoms out (latched keys rest at 55%).
spring{ stiffness: number; damping: number; mass: number }{ stiffness: 700, damping: 22, mass: 0.6 }Spring for the return stroke.
clackbooleantrueFlash an accent ring and a highlight as the key bottoms out.
pressedboolean—Controlled latch state; makes the key a toggle with aria-pressed.
defaultPressedbooleanfalseInitial latch state for an uncontrolled toggle.
togglebooleanfalseMake an uncontrolled key latch on each press.
onPressedChange(pressed: boolean) => void—Called with the next latch state.
...propsButtonHTMLAttributes—Forwarded to the <button>; the ref points to it.

04Features

  • 01Layered skirt and inset top surface with profile-specific depth and a dished highlight
  • 02Down stroke bottoms out without overshoot; the return stroke uses your spring
  • 03Contact shadow tightens as the cap travels
  • 04Optional clack: an accent ring and a soft flash at bottom-out
  • 05Text or glyph legends, sub-legends and three legend positions
  • 06Latching toggle keys with a status LED
  • 07Any width in keyboard units; four colourways including auto light / dark
motion · springinput · pressinput · clickinput · keyboard

05Accessibility

  • A native <button>: Enter and Space trigger it and play the same press animation as the pointer.
  • Toggle keys expose aria-pressed and rest partway down with a lit LED, so the state is visible without colour alone.
  • label provides the accessible name for glyph legends (⌘ → "Command"); the printed legends are then hidden from assistive tech.
  • Visible focus-visible ring in the accent colour, offset from the cap.
  • With prefers-reduced-motion the cap moves instantly and the clack flash is skipped.