Skeleton Handoff
Skeleton Handoff measures matching loading blocks and real content, then uses GSAP Flip to move each block into place while revealing the content. Cached results render directly, short loads skip the skeleton, and refetches crossfade without reversing the handoff.
Dependencies
gsap@gsap/reactclsxtailwind-merge
Interaction
A root-level handoff pairs the first block and target for each data-handoff-id. Flip.fit animates each solid block to its target rectangle while real content fades in unscaled. The root height eases once to the measured content height, then all temporary inline animation styles are removed.
Props
| Prop | Type | Description |
|---|---|---|
| status | "loading" | "ready" | "error" | Controls the skeleton, handoff, and error states. |
| skeleton | React.ReactNode | Skeleton markup containing HandoffBlock elements. |
| children | React.ReactNode | Content rendered when ready and measured during handoff. |
| duration | number | Travel duration in seconds. |
| stagger | number | Delay between blocks, in seconds. |
| skipBelow | number | Delay in milliseconds before the skeleton becomes visible. |
| loadingLabel | string | Polite live-region text while data is loading. |
| readyLabel | string | Polite live-region text when data becomes ready. |
| errorLabel | string | Visible alert text when the request fails. |
| onHandoffStart | () => void | Called when a loading-to-ready handoff begins. |
| onHandoffComplete | () => void | Called after the handoff animation completes. |
| className | string | Additional classes for the root element. |
| HandoffBlock | { id: string; className?: string; as?: React.ElementType } | Creates a solid skeleton block with a matching identifier. |
| HandoffTarget | { id: string; className?: string; as?: React.ElementType; children: React.ReactNode } | Marks real content that matches a skeleton block. |
MIT License. Free to use in personal and commercial projects. Built for Peel UI.