Lock Open
A small, hoverable open-padlock icon. On hover (or focus) the shackle pulls upward by drawing its path to full length, and the body gives a tiny wobble-and-pop — the canonical "click to unlock" affordance. Two-state spring motion routed through SPRINGS.damped (shackle) and SPRINGS.bouncy (body), so transitions are interruptible and respect the 300ms ceiling.
Customize
Lock
28px
accent (token)
Installation
npx shadcn@latest add https://craftbits.dev/r/lock-open.jsonUsage
import { LockOpen } from "@craft-bits/core/svg/lock-open";
<LockOpen size={28} />Understanding the component
- Two-state springs, not keyframes. The icon animates between exactly two states — rest and hover. Both the body wobble and the shackle path-length interpolate via
SPRINGS.bouncy/SPRINGS.damped, so hovering off mid-flight reverses the motion smoothly instead of snapping back to the rest pose. - Reduced-motion fallback. When the OS-level
prefers-reduced-motionsetting is on — orpausedis set explicitly — the icon renders the rest-state glyph with no transitions. The padlock stays legible; only the motion disappears. - Hover and focus share the same trigger. Keyboard users get the same affordance as pointer users: focusing the tile triggers the same shackle-draw + body wobble.
- Stripped from the source. The terminal-dreams source exposed an imperative
LockOpenIconHandleref API (startAnimation/stopAnimation). The library version drops it: the ref now forwards to the underlying tile span, matching every other@craft-bits/core/svg/*primitive. Drive motion viapausedinstead.
Variants / Examples
// Default — uses the cb-fg foreground colour and accent token on hover.
<LockOpen />
// Larger glyph (the inner SVG scales — the tile stays 48px).
<LockOpen size={36} />
// Override the hover-border accent.
<LockOpen accentColor="#10b981" />
// Force the static fallback (e.g. inside a print stylesheet).
<LockOpen paused />Props
| Prop | Type | Default | Description |
|---|---|---|---|
size | number | 28 | Pixel diameter of the inner SVG glyph. |
accentColor | string | var(--cb-color-accent) | Border tint applied on hover / focus. |
paused | boolean | false | When true, skip animations and render the rest-state glyph. |
className | string | — | Extra classes merged onto the outer tile span. |
...rest | HTMLAttributes<HTMLSpanElement> | — | Forwarded to the root tile span (except onMouseEnter / onMouseLeave, which the component owns). |
Accessibility
- The tile and inner SVG are marked
aria-hidden="true"by default — the lock is a decorative micro-interaction. If it stands alone as a button, wrap it in a<button>with anaria-label(e.g. "Unlock entry"). - Hover and focus both trigger the animation, so keyboard users get the same affordance as pointer users.
usePrefersReducedMotionshort-circuits every animation when the OS-level setting is on; the icon falls back to a static glyph automatically.- Colour tinting flows from
currentColorfor the glyph and the--cb-color-accenttoken for the hover border, so the icon inherits whatever contrast the wrapping surface already meets.
Credits
- Extracted from:
terminal-dreams(src/components/ui/lock-open.tsx). - Inspiration:
pqoqubbw/iconsopen-source animated icon set.