Anatomy of the GodUI Sheet
How one shared slide keyframe travels a whole panel, and why overriding its distance can't break reduced motion.
↓Scroll to step through it
Full-distance slides
The shared godui-slide-in-from-* keyframes move an element by
--godui-enter-distance, which defaults to 0.5rem: a nudge, right for
menus and toasts. A sheet needs to travel its whole width.
So the sheet sets --godui-enter-distance: 100% on itself. A percentage in
translate resolves against the element's own size, so the panel starts
exactly one width off-screen whatever its width is, then springs in.
Reduced motion still wins
Overriding a token locally usually lets a component escape the
reduced-motion setting. The sheet can't, because the keyframe multiplies the distance by
--godui-motion, which only :root sets, and sets it to 0 under
prefers-reduced-motion. The sheet can say "100%", and the multiplier still
turns that into zero.
Left and right sheets enter on ease-spring-smooth over 380ms: a softer,
longer spring, because a large surface moving fast feels abrupt.
The result
Open the sheet, then close it with Escape or the Close button. The exit uses
ease-out-expo: it leaves faster than it arrived.
- translate
- 100% 0 → 0 0
- opacity
- 0 → 1
<SheetPrimitive.Contentdata-slot="sheet-content"className={cn( "fixed z-50 flex flex-col gap-4 bg-background shadow-lg [--godui-enter-distance:100%]", side === "right" && "inset-y-0 right-0 h-full w-3/4 border-l data-[state=open]:animate-godui-slide-in-from-right data-[state=closed]:animate-godui-slide-out-to-right sm:max-w-sm", // left, top, bottom: same pattern className,)}/>Anatomy of the GodUI Sheet
How one shared slide keyframe travels a whole panel, and why overriding its distance can't break reduced motion.
- translate
- 100% 0 → 0 0
- opacity
- 0 → 1
<SheetPrimitive.Contentdata-slot="sheet-content"className={cn( "fixed z-50 flex flex-col gap-4 bg-background shadow-lg [--godui-enter-distance:100%]", side === "right" && "inset-y-0 right-0 h-full w-3/4 border-l data-[state=open]:animate-godui-slide-in-from-right data-[state=closed]:animate-godui-slide-out-to-right sm:max-w-sm", // left, top, bottom: same pattern className,)}/>Full-distance slides
The shared godui-slide-in-from-* keyframes move an element by
--godui-enter-distance, which defaults to 0.5rem: a nudge, right for
menus and toasts. A sheet needs to travel its whole width.
So the sheet sets --godui-enter-distance: 100% on itself. A percentage in
translate resolves against the element's own size, so the panel starts
exactly one width off-screen whatever its width is, then springs in.
ease-spring-smooth
@keyframes godui-slide-in-from-right {from { opacity: 0; translate: calc(var(--godui-enter-distance) * var(--godui-motion)) 0;}}@media (prefers-reduced-motion: reduce) {:root { --godui-motion: 0; }}Reduced motion still wins
Overriding a token locally usually lets a component escape the
reduced-motion setting. The sheet can't, because the keyframe multiplies the distance by
--godui-motion, which only :root sets, and sets it to 0 under
prefers-reduced-motion. The sheet can say "100%", and the multiplier still
turns that into zero.
Left and right sheets enter on ease-spring-smooth over 380ms: a softer,
longer spring, because a large surface moving fast feels abrupt.
The result
Open the sheet, then close it with Escape or the Close button. The exit uses
ease-out-expo: it leaves faster than it arrived.
What's animated
| Interaction | Keyframe / mechanism | Properties | Easing | Duration |
|---|---|---|---|---|
| Open (left, right) | godui-slide-in-from-* | translate 100% → 0, opacity | ease-spring-smooth | 380ms |
| Open (top, bottom) | godui-slide-in-from-* | translate 100% → 0, opacity | ease-spring-snappy | 260ms |
| Close | godui-slide-out-to-* | translate, opacity | ease-out-expo | 260 / 150ms |
| Overlay | godui-fade-in / godui-fade-out | opacity | snappy / expo | 260 / 150ms |
shadcn's sheet also sets a bare transition class, which would animate color,
border and shadow changes. GodUI drops it.
Why GPU-only
The panel animates translate and opacity; the overlay animates opacity.
shadcn's sheet also carries a bare transition class, which would animate
color, border and shadow paint if they changed. GodUI removes it.
Reduced motion
--godui-motion: 0 zeroes the slide distance, so the panel fades in place for
150ms.
Replacing shadcn
npx shadcn add @godui/sheet overwrites components/ui/sheet.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.