Getting started
Foundations
Integrations
Form19
Display5
Layout4
Navigation4
Overlay8
Feedback4
Motion19
#Installation
npx @dinachi/cli@latest add load-transition#Usage
tsx
import { LoadTransition } from "@/components/ui/load-transition"tsx
<LoadTransition loading={isLoading} skeleton={<Placeholder />}>
<DeploymentSummary data={data} />
</LoadTransition>#Examples
#The skeleton-to-content jump
Almost nobody treats this as an animation. The skeleton is removed, the real content is inserted at a different height, and everything below it jumps. The skeleton was supposed to be preventing exactly that.
Three things fix it, and only two of them are motion.
| Fix | Why it works |
|---|---|
| The container animates its own height across the swap | The page below settles instead of snapping. It is motion's layout animation, so the height change is a transform with a scale correction on the children rather than a real height tween, which keeps it off the main thread. |
| The skeleton leaves faster than the content arrives: 120ms out against 260ms in | There is never a frame with both at full strength, and never one with neither. A skeleton lingering over the real text is worse than a hard swap. |
| A skeleton that appears and disappears inside 150ms never appears at all | A flash is worse than the wait it was hiding. That one is timing, not animation. |
#Two thresholds, solving opposite problems
| Prop | Default | What it prevents |
|---|---|---|
delay | 180 | Nothing shows for the first 180ms. A request that returns in 120ms goes straight to content; a placeholder shown for two frames reads as a glitch, not as feedback. |
minimum | 420 | Once shown, the skeleton stays. A placeholder that appears and vanishes immediately is the same flash arriving from the other direction. |
They are not motion, so reduced motion does not remove them.
useSkeletonVisibility(loading, delay, minimum) is exported on its own if you want the same
two thresholds somewhere this component does not fit.
#The radius is an inline style
radius is a number in px, applied inline, not a class.
Motion can only counteract the distortion its own scale introduces on a value it is animating, and a class is invisible to it. As a class the corners visibly stretch during the resize.
#When to use it
| Use it for | Not for |
|---|---|
| A region whose loaded height differs from its placeholder: a summary, a card, a detail panel. | A full-page load. There is nothing below it to protect from the jump. |
| Anywhere a skeleton already exists and is causing a reflow when it leaves. | Content that streams in piece by piece. That is a different problem, and this component swaps once. |
#Behaviour
- The swap is
mode="popLayout", so the leaving skeleton is pulled out of flow immediately and the arriving content does not wait behind it. - Both children carry
layout, so the parent's scale is undone on them rather than squashing the rows inside. - Reduced motion drops the travel and the resize, and keeps the crossfade. The handover is still a handover; it just does not move.
#API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| loading | boolean | — | Whether the data is still on its way. Not the same as whether the skeleton is on screen |
| skeleton | ReactNode | — | The placeholder shown while waiting |
| delay | number | 180 | Milliseconds of loading before the skeleton appears at all. A faster load goes straight to content |
| minimum | number | 420 | Milliseconds the skeleton is held once shown, so it cannot flash |
| radius | number | 12 | Corner radius in px. A number, not a class — motion can only correct a value it is animating |