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.
↓Scroll to step through it
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.
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.
The result
Press and hold a toggle, then release to switch it.
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 */ } },);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.
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 */ } },);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.
// 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"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.
The result
Press and hold a toggle, then release to switch it.
What's animated
| Interaction | Keyframe / mechanism | Properties | Easing | Duration |
|---|---|---|---|---|
| Press | transition on active:scale-[0.96] | scale | ease-spring-bouncy | 260ms |
| On / off, hover | snaps | none | none | none |
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.