KQ-1258 · LATCH/LOCK
Latch Lock
A lock toggle drawn as a padlock whose parts move on their own springs: unlocking lifts the shackle on the snap spring and swings it out about its long leg with one overshoot while the body drops a few pixels and a glint sweeps the keyhole; locking swings it back and drops it home on the flick spring against a hard stop, with a short shake through the whole lock. A disabled lock stays focusable, rattles in place and says why instead of toggling. Space and Enter toggle it through the native click, and aria-pressed reports locked.
KQ-1258 · LATCH/LOCK
Debit card
···· 4821
card locked · new payments declined
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/latch-lock
Props
- pressed / defaultPressed
- boolean
- default true
- Locked state, controlled or initial; true is locked.
- onPressedChange
- (locked: boolean) => void
- default —
- Fires from the press that changed it.
- lockedLabel
- string
- default "Locked"
- Text and accessible name while locked.
- unlockedLabel
- string
- default "Unlocked"
- Text and accessible name while unlocked; the button keeps the wider label's width.
- compact
- boolean
- default false
- Icon only, with the label as the accessible name.
- weight
- number
- default 0.5
- How heavy the lock is, 0 to 1: slower swing, deeper drop, lower thock.
- rattle
- number
- default 0.5
- How hard the lock shakes as the shackle seats and when a disabled lock is pressed.
- glint
- number
- default 0.6
- Strength of the keyhole glint on unlocking; 0 hides it.
- swing
- number
- default 26
- How far the open shackle swings out, in degrees.
- size
- "sm" | "md" | "lg"
- default "md"
- Button height 32, 40 or 48 px with the padlock scaled to match.
- lockedColor
- string
- default "var(--accent-bright)"
- The body's colour while locked and the pressed tint; any CSS colour.
- unlockedColor
- string
- default "var(--ink-3)"
- The body's colour while unlocked.
- disabledNote
- string
- default "This lock can't be changed right now"
- Spoken in a polite live region when a disabled lock is pressed.
- onRefused
- () => void
- default —
- A press on a disabled lock, after it rattled and stayed put.
- sound
- boolean
- default false
- Clack as the shackle lets go, thock as it seats, muted clacks for a refusal.
- disabled
- boolean
- default false
- Rattles instead of toggling; stays in the tab order via aria-disabled.
- className
- string
- default —
- Classes for the wrapper.
| Prop | Type | Default | Description |
|---|---|---|---|
| pressed / defaultPressed | boolean | true | Locked state, controlled or initial; true is locked. |
| onPressedChange | (locked: boolean) => void | — | Fires from the press that changed it. |
| lockedLabel | string | "Locked" | Text and accessible name while locked. |
| unlockedLabel | string | "Unlocked" | Text and accessible name while unlocked; the button keeps the wider label's width. |
| compact | boolean | false | Icon only, with the label as the accessible name. |
| weight | number | 0.5 | How heavy the lock is, 0 to 1: slower swing, deeper drop, lower thock. |
| rattle | number | 0.5 | How hard the lock shakes as the shackle seats and when a disabled lock is pressed. |
| glint | number | 0.6 | Strength of the keyhole glint on unlocking; 0 hides it. |
| swing | number | 26 | How far the open shackle swings out, in degrees. |
| size | "sm" | "md" | "lg" | "md" | Button height 32, 40 or 48 px with the padlock scaled to match. |
| lockedColor | string | "var(--accent-bright)" | The body's colour while locked and the pressed tint; any CSS colour. |
| unlockedColor | string | "var(--ink-3)" | The body's colour while unlocked. |
| disabledNote | string | "This lock can't be changed right now" | Spoken in a polite live region when a disabled lock is pressed. |
| onRefused | () => void | — | A press on a disabled lock, after it rattled and stayed put. |
| sound | boolean | false | Clack as the shackle lets go, thock as it seats, muted clacks for a refusal. |
| disabled | boolean | false | Rattles instead of toggling; stays in the tab order via aria-disabled. |
| className | string | — | Classes for the wrapper. |