GodUIGodUI
129Follow on X

Anatomy of the GodUI Sheet

How one shared slide keyframe travels a whole panel, and why overriding its distance can't break reduced motion.

01/03Full-distance slides
translate
100% 0 → 0 0
opacity
0 → 1
tsx
<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,)}/>
01

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.

02/03Reduced motion still wins

ease-spring-smooth

tsx
@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; }}
02

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.

03/03Result
03

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

InteractionKeyframe / mechanismPropertiesEasingDuration
Open (left, right)godui-slide-in-from-*translate 100% → 0, opacityease-spring-smooth380ms
Open (top, bottom)godui-slide-in-from-*translate 100% → 0, opacityease-spring-snappy260ms
Closegodui-slide-out-to-*translate, opacityease-out-expo260 / 150ms
Overlaygodui-fade-in / godui-fade-outopacitysnappy / expo260 / 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.