Buttons. Sized, toned, animated.
One .lsd-btn component with independent size, tone, and
shape modifier classes. 20 stackable animations · 10 styles · all
surface-aware — chain what you need, each effect is a separate concern.
Animations are universal — .lsd-fx--lift, .lsd-fx--shimmer,
and friends chain onto any LSD primitive (inputs, chips, cards). Button-specific
text choreography — .lsd-btn--arrow-lurch, .lsd-btn--slide-swap,
.lsd-btn--flip — stays scoped because it needs button inner markup.
.lsd-btn
The component is layout + tokens. --btn-bg, --btn-fg,
--btn-radius, --btn-pad-*, --btn-font are CSS
variables — tones and sizes override them. No raw colors hardcoded; the surface
contract from the broader framework still applies.
primary / ghost / outlined / soft / danger
Five tone modifiers swap --btn-bg, --btn-fg, and --btn-border via CSS vars. The shape doesn't change.
<button class="lsd-btn lsd-btn--primary">Primary</button> <button class="lsd-btn lsd-btn--ghost">Ghost</button> <button class="lsd-btn lsd-btn--outlined">Outlined</button>
sm / md (default) / lg / xl
Size mods shift padding + font-size only. Tone stays whatever you pair it with.
<button class="lsd-btn lsd-btn--sm">Small</button> <button class="lsd-btn lsd-btn--lg">Large</button>
default / pill / icon
Shape mods alter radius and footprint. Icon shape forces a square footprint at the active size.
<button class="lsd-btn lsd-btn--pill">Pill</button> <button class="lsd-btn lsd-btn--icon" aria-label="Settings">⚙</button>
disabled / focus / active
[disabled] dims and removes shadow. Focus ring uses the secondary accent so it reads on any tone.
<button class="lsd-btn" disabled>Disabled</button>
Ten button styles
Style variants change structure or surface character — distinct from tone (which only swaps color tokens). Each is a single class; combine with sizes, tones, and animations freely.
Bracket framing
Monospace [ ] bracket chars fade in around the label on hover. Terminal aesthetic.
<button class="lsd-btn lsd-btn--ghost
lsd-btn--brackets">
run command
</button>
Status dot chip
Bullet dot with a soft glow before the label. Works for status, filter chips, or live indicators.
<button class="lsd-btn lsd-btn--soft
lsd-btn--dot-tag">
Live
</button>
Arrow pill
Pill button with a permanent circular arrow chip. The arrow nudges forward on hover.
<button class="lsd-btn lsd-btn--primary
lsd-btn--arrow-pill">
<span>Get started</span>
<span class="lsd-btn__arrow">→</span>
</button>
Circular bezel
96px circular badge button — primary + small caption. Inner bezel glow uses accent.
<button class="lsd-btn lsd-btn--circle-bezel"> <span>Play</span> <span class="lsd-btn__sub">2:14</span> </button>
Two-line label
Primary label + supporting line. Common for menu items, action lists, or call buttons.
<button class="lsd-btn lsd-btn--two-line"> <span class="lsd-btn__label">Continue</span> <span class="lsd-btn__sub">3 items</span> </button>
Keyboard shortcut
Inline <kbd> showing the trigger key. Useful in command palettes and toolbars.
<button class="lsd-btn lsd-btn--ghost
lsd-btn--kbd-shortcut">
Search<kbd>⌘K</kbd>
</button>
Split action
Main action + dropdown caret as a single rounded shell. Two buttons, one perceived unit.
<div class="lsd-btn-split">
<button class="lsd-btn lsd-btn--primary">
Deploy
</button>
<button class="lsd-btn lsd-btn--primary
lsd-btn--caret">▾</button>
</div>
Icon-leading shift
Icon on the left of the label, slides back by 2px on hover. Tiny detail, lots of polish.
<button class="lsd-btn lsd-btn--outlined
lsd-btn--icon-leading">
<span class="lsd-btn__icon">↗</span>
<span>Open</span>
</button>
Animated gradient rim
Conic gradient border slowly rotates around the button. Pauses for prefers-reduced-motion.
<button class="lsd-btn lsd-btn--gradient-rim
lsd-btn--lg">
Upgrade plan
</button>
Frosted glass
backdrop-filter: blur + saturate over a tinted accent surface. Best over imagery.
<button class="lsd-btn lsd-btn--glass"> Continue </button>
Stack a behavior
20 stackable animations · 10 styles · all surface-aware. Each variant is an independent modifier class. Chain them with sizes/tones — every animation works against any base. Grouped below by character.
Press feedback
Press squish
Compresses vertically on :active, snaps back with overshoot cubic-bezier.
<button class="lsd-btn lsd-btn--lg
lsd-fx--squish">
Press me
</button>
Bounce pop
Scale-bounce on hover using cubic-bezier(0.34, 1.56, 0.64, 1) overshoot.
<button class="lsd-btn lsd-btn--soft
lsd-fx--pop">
Pop!
</button>
Elastic wobble
Three-frame rotate-shake keyframe on hover. Disabled for reduced-motion users.
<button class="lsd-btn lsd-btn--danger
lsd-fx--wobble">
Wobble
</button>
Pointer follow
Cursor pull
JS reads pointer offset and writes --mx/--my. Translates ~32% toward cursor.
<button class="lsd-btn lsd-fx--magnetic"> Pull me </button>
3D perspective tilt
JS reads pointer offset, writes --rx/--ry. Button tilts in 3D space.
<button class="lsd-btn lsd-btn--xl
lsd-fx--tilt">
Tilt me
</button>
Surface reveal
Hover lift + bloom
3px translate-up on hover, dual-color shadow bloom from accent + accent-3.
<button class="lsd-btn lsd-fx--lift"> Hover me </button>
Shimmer sweep
Diagonal light stripe sweeps across on hover. Pure CSS.
<button class="lsd-btn lsd-fx--shimmer"> Hover me </button>
Slide fill from bottom
Accent floods up from the bottom edge on hover, swapping foreground for legibility.
<button class="lsd-btn lsd-fx--slide-fill"> Hover me </button>
Border draw-on
Conic gradient stroke animates around the outline via @property angle interpolation.
<button class="lsd-btn lsd-fx--border-draw"> Hover me </button>
Underline grow
Accent underline expands left-to-right on hover. Reads like a link with weight.
<button class="lsd-btn lsd-fx--underline-grow"> Read article </button>
Text choreography
Arrow lurch
Label slides left, arrow slides right on hover. Adds tension to a call-to-action.
<button class="lsd-btn lsd-btn--arrow-lurch"> <span class="lsd-btn__label">Continue</span> <span class="lsd-btn__arrow">→</span> </button>
Label slide-swap
Label slides up out, hover label slides up in via data-hover-label.
<button class="lsd-btn lsd-btn--slide-swap"
data-hover-label="Let's go ↗">
<span class="lsd-btn__label">Get started</span>
</button>
Letter stagger lift
Each letter rises sequentially via --lsd-stagger-index delay. JS splits on mount.
<button class="lsd-btn lsd-fx--letter-stagger"> Animate me </button>
Letter shuffle
Letters scramble through random glyphs for ~450ms on hover, then settle to the real text.
<button class="lsd-btn lsd-fx--letter-shuffle"
data-text="DECRYPT">
DECRYPT
</button>
RGB glitch
Cyan + magenta channel split with clip-path jitter on hover. Pure CSS.
<button class="lsd-btn lsd-fx--glitch">
<span class="lsd-fx__text"
data-text="SIGNAL">SIGNAL</span>
</button>
Click + idle
Material ripple
Circle expands from the click point. JS injects a span, removes on animationend.
<button class="lsd-btn lsd-fx--ripple-click"> Click me </button>
Breathing halo
Continuous box-shadow pulse — useful as an idle attractor. Paused for reduced-motion.
<button class="lsd-btn lsd-fx--glow-pulse"> Pay now </button>
Ink-drop flood
Colored circle floods slowly from the click point — slower + bolder than the ripple.
<button class="lsd-btn lsd-fx--ink-drop"> Confirm </button>
3D card flip
Front face flips to back on hover. Uses preserve-3d + backface-visibility.
<button class="lsd-btn lsd-btn--flip">
<span class="lsd-btn__face-wrap">
<span class="lsd-btn__front">Add</span>
<span class="lsd-btn__back">View →</span>
</span>
</button>
Goo blob morph
SVG goo filter merges two pseudo-blobs into the button shell on hover. Liquid feel.
<button class="lsd-btn lsd-fx--goo-morph"> Goo </button>
Chain four behaviours
Lift + shimmer + magnetic + ripple-click on one button. Independent classes, no conflict.
<button class="lsd-btn lsd-btn--xl
lsd-fx--lift
lsd-fx--shimmer
lsd-fx--magnetic
lsd-fx--ripple-click">
Stack four ↗
</button>