Anatomy of the GodUI Toggle Group
A single-select toggle group is a segmented control, so it gets the same sliding indicator as Tabs from one shared hook.
↓Scroll to step through it
A segmented control
When only one item can be on, the group reads as a single control with a
moving selection, so GodUI gives it one indicator. It slides from the old
item to the new one: its box snaps to the new item, then a FLIP animates
translate and scale back from the old box.
With type="multiple", several items can be on at once and there's no
single target, so the hook is disabled and each item paints its own on
background.
Shared with Tabs
The indicator logic is the same hook that drives Tabs
and Command's selection. It watches the active item's attributes, so
clicks, arrow keys and controlled value changes all move it. Inserted or
resized items snap it into place. Until it has measured once, it leaves the
container without data-indicator="ready", and the pressed item keeps
shadcn's own background.
The result
Click between alignments, or focus the group and use the arrow keys plus Space.
const single = props.type === "single" && !props.asChild;useActiveIndicator(rootRef, indicatorRef, {active: '[data-slot="toggle-group-item"][data-state="on"]',items: '[data-slot="toggle-group-item"]',enabled: single,});Anatomy of the GodUI Toggle Group
A single-select toggle group is a segmented control, so it gets the same sliding indicator as Tabs from one shared hook.
const single = props.type === "single" && !props.asChild;useActiveIndicator(rootRef, indicatorRef, {active: '[data-slot="toggle-group-item"][data-state="on"]',items: '[data-slot="toggle-group-item"]',enabled: single,});A segmented control
When only one item can be on, the group reads as a single control with a
moving selection, so GodUI gives it one indicator. It slides from the old
item to the new one: its box snaps to the new item, then a FLIP animates
translate and scale back from the old box.
With type="multiple", several items can be on at once and there's no
single target, so the hook is disabled and each item paints its own on
background.
// hooks/use-active-indicator.ts (ships in godui-motion)export function useActiveIndicator(containerRef: React.RefObject<HTMLElement | null>,indicatorRef: React.RefObject<HTMLElement | null>,options: ActiveIndicatorOptions,): voidShared with Tabs
The indicator logic is the same hook that drives Tabs
and Command's selection. It watches the active item's attributes, so
clicks, arrow keys and controlled value changes all move it. Inserted or
resized items snap it into place. Until it has measured once, it leaves the
container without data-indicator="ready", and the pressed item keeps
shadcn's own background.
The result
Click between alignments, or focus the group and use the arrow keys plus Space.
What's animated
| Interaction | Keyframe / mechanism | Properties | Easing | Duration |
|---|---|---|---|---|
| Select (single) | FLIP (WAAPI) on the indicator | translate, scale | ease-spring-snappy | 260ms |
| Toggle (multiple) | on background snaps | none | none | none |
| Press | transition on active:scale-[0.96] | scale | ease-spring-bouncy | 260ms |
Before JavaScript runs, the pressed item paints its own background, exactly as in shadcn.
Why GPU-only
The indicator animates translate and scale; presses animate scale.
shadcn's items transition color and box-shadow; GodUI's don't.
Reduced motion
The indicator jumps to the new item without sliding, and presses are instant.
Replacing shadcn
npx shadcn add @godui/toggle-group overwrites components/ui/toggle-group.tsx
and installs the GodUI Toggle it styles items with.
Exports, props and data-slot attributes match shadcn/ui new-york-v4, so
existing imports keep working. A single-select group renders one extra element,
an aria-hidden <span data-slot="toggle-group-indicator">.