Anatomy of the GodUI Select
Two positioning modes share one keyframe, and the check mark pops each time the list reopens on your choice.
↓Scroll to step through it
Item-aligned vs popper
By default (position="item-aligned") Radix places the list so the selected
option sits right over the trigger, like a native macOS menu. In that mode
Radix sets no data-side, so the drift variables stay at 0 and the list
only scales and fades into place.
With position="popper" the list opens below or above the trigger like a
popover. Radix sets data-side, the drift variables kick in, and the list
slides 4px out of the trigger as it grows: the same godui-popover-in
keyframe, with the extra drift only in popper mode.
The check
Radix renders the selected item's indicator only for that item. Every time the list opens, the check next to your current value pops in from half size, a small confirmation of what's selected as the list appears.
The result
Open the select, pick a fruit, then reopen it to see the check on your choice.
- opacity
- 0 → 1
- scale
- 0.96 → 1
- translate (popper)
- 0 -4px → 0 0
<SelectPrimitive.Contentdata-slot="select-content"className={cn( "relative z-50 … origin-(--radix-select-content-transform-origin) … data-[side=bottom]:[--godui-enter-y:-0.25rem] … data-[state=open]:animate-godui-popover-in data-[state=closed]:animate-godui-popover-out", position === "popper" && "data-[side=bottom]:translate-y-1 …", className,)}position={position}/>Anatomy of the GodUI Select
Two positioning modes share one keyframe, and the check mark pops each time the list reopens on your choice.
- opacity
- 0 → 1
- scale
- 0.96 → 1
- translate (popper)
- 0 -4px → 0 0
<SelectPrimitive.Contentdata-slot="select-content"className={cn( "relative z-50 … origin-(--radix-select-content-transform-origin) … data-[side=bottom]:[--godui-enter-y:-0.25rem] … data-[state=open]:animate-godui-popover-in data-[state=closed]:animate-godui-popover-out", position === "popper" && "data-[side=bottom]:translate-y-1 …", className,)}position={position}/>Item-aligned vs popper
By default (position="item-aligned") Radix places the list so the selected
option sits right over the trigger, like a native macOS menu. In that mode
Radix sets no data-side, so the drift variables stay at 0 and the list
only scales and fades into place.
With position="popper" the list opens below or above the trigger like a
popover. Radix sets data-side, the drift variables kick in, and the list
slides 4px out of the trigger as it grows: the same godui-popover-in
keyframe, with the extra drift only in popper mode.
- scale
- 0.5 → 1
- opacity
- 0 → 1
<span data-slot="select-item-indicator" className="absolute right-2 flex size-3.5 items-center justify-center"><SelectPrimitive.ItemIndicator className="[--godui-enter-scale:0.5] animate-godui-fade-scale-in"> <CheckIcon className="size-4" /></SelectPrimitive.ItemIndicator></span>The check
Radix renders the selected item's indicator only for that item. Every time the list opens, the check next to your current value pops in from half size, a small confirmation of what's selected as the list appears.
The result
Open the select, pick a fruit, then reopen it to see the check on your choice.
What's animated
| Interaction | Keyframe / mechanism | Properties | Easing | Duration |
|---|---|---|---|---|
| Open | godui-popover-in | opacity, scale 0.96 → 1; translate toward the trigger in popper mode | ease-spring-snappy | 260ms |
| Close | godui-popover-out | the same, reversed | ease-out-expo | 150ms |
| Selected check | godui-fade-scale-in from 50% | scale, opacity | ease-spring-snappy | 260ms |
| Trigger hover / focus | snaps | none | none | none |
Why GPU-only
The list animates opacity, scale and translate; the check animates
scale and opacity. shadcn's trigger transitions color and box-shadow;
GodUI's snaps.
Reduced motion
--godui-motion: 0 removes scale and drift, so the list and the check only
fade, in 150ms.
Replacing shadcn
npx shadcn add @godui/select overwrites components/ui/select.tsx. Exports,
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.