Skip to content
LSD Framework
Components · primitives

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.

01 · base

.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.

tones

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>
sizes

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>
shapes

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>
states

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>
02 · styles

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.

.lsd-btn--brackets

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>
.lsd-btn--dot-tag

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>
.lsd-btn--arrow-pill

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>
.lsd-btn--circle-bezel

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>
.lsd-btn--two-line

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>
.lsd-btn--kbd-shortcut

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>
.lsd-btn-split

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>
.lsd-btn--icon-leading

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>
.lsd-btn--gradient-rim

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>
.lsd-btn--glass

Frosted glass

backdrop-filter: blur + saturate over a tinted accent surface. Best over imagery.

<button class="lsd-btn lsd-btn--glass">
  Continue
</button>
03 · animations

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

.lsd-fx--squish

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>
.lsd-fx--pop

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>
.lsd-fx--wobble

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

.lsd-fx--magnetic

Cursor pull

JS reads pointer offset and writes --mx/--my. Translates ~32% toward cursor.

<button class="lsd-btn lsd-fx--magnetic">
  Pull me
</button>
.lsd-fx--tilt

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

.lsd-fx--lift

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>
.lsd-fx--shimmer

Shimmer sweep

Diagonal light stripe sweeps across on hover. Pure CSS.

<button class="lsd-btn lsd-fx--shimmer">
  Hover me
</button>
.lsd-fx--slide-fill

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>
.lsd-fx--border-draw

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>
.lsd-fx--underline-grow

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

.lsd-btn--arrow-lurch

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>
.lsd-btn--slide-swap

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>
.lsd-fx--letter-stagger

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>
.lsd-fx--letter-shuffle

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>
.lsd-fx--glitch

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

.lsd-fx--ripple-click

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>
.lsd-fx--glow-pulse

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>
.lsd-fx--ink-drop

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>
.lsd-btn--flip

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>
.lsd-fx--goo-morph

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>
combo

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>
Components · Buttons · 20 animations · 10 styles
↩ Framework index