GodUIGodUI
129Follow on X

Anatomy of the GodUI Toggle

A press on a spring, a background that snaps, and a scoped selector that lets the same toggle hand its background to a group's sliding indicator.

01/03The press
tsx
const toggleVariants = cva("… whitespace-nowrap outline-none transition-[scale] duration-(--godui-duration-base) ease-spring-bouncy active:scale-[0.96] motion-reduce:transition-none …",{ variants: { /* unchanged from shadcn */ } },);
01

The press

The toggle shares Button's press: active:scale-[0.96] on the bouncy spring, with transition-[scale] so nothing else animates. shadcn's transition-[color,box-shadow] is gone, so hover, focus ring and the on/off background change instantly.

02/03A background that can step aside
tsx
// toggle.tsx: unchanged from shadcn, so call-site overrides merge as before"data-[state=on]:bg-accent"// toggle-group.tsx, on each item: once the group's indicator is measured"in-[[data-slot=toggle-group][data-indicator=ready]]:data-[state=on]:bg-transparent"
02

A background that can step aside

A single-select Toggle Group draws its selection with one sliding indicator, so its pressed item must not paint its own background on top. A standalone toggle has no indicator and must keep its background.

So the toggle keeps shadcn's data-[state=on]:bg-accent exactly. A call site's own data-[state=on]:bg-* still replaces it through cn(), as with shadcn. The group item, not the toggle, adds the override: once the group reports data-indicator="ready", its pressed item turns transparent and the indicator shows through. Before that, on the server and at first paint, the item looks exactly like shadcn's.

03/03Result
03

The result

Press and hold a toggle, then release to switch it.

What's animated

InteractionKeyframe / mechanismPropertiesEasingDuration
Presstransition on active:scale-[0.96]scaleease-spring-bouncy260ms
On / off, hoversnapsnonenonenone

Why GPU-only

The press animates scale. The on background, hover background and focus ring change instantly instead of transitioning color and box-shadow.

Reduced motion

motion-reduce:transition-none makes the press instant.

Replacing shadcn

npx shadcn add @godui/toggle overwrites components/ui/toggle.tsx. Exports (Toggle, toggleVariants), props and data-slot attributes match shadcn/ui new-york-v4, so existing imports keep working. It also installs godui-motion (easings, keyframes, the FLIP hook) into your project.