Skeleton from @prepared911/ui/skeleton reserves space for content that hasn't loaded yet. The component surfaces a loading label by default; your job is to keep the announcement sensible, swap skeletons for real content promptly, and honor reduced motion.
What the component handles
Loading label. Skeletons expose aria-label="Loading content" (localized) so screen readers announce the state.
Shape presets. Text-line, paragraph, circle, and block shapes echo the target layout.
Animation. A gentle shimmer reinforces the wait without implying progress.
What you must provide
Contextual label. For region-specific skeletons, pass a descriptive label ("Loading incident list", "Loading profile") so the rotor knows what will appear.
A single loading announcement. Don't render ten individual skeletons, each announcing "loading"; wrap a cluster in one aria-busy container with a single label.
Prompt replacement. Skeletons are a stand-in; swap to real content as soon as data arrives to avoid lingering placeholders.
Semantics and roles
Skeletons render with aria-label and are non-focusable.
Wrapping container should expose aria-busy="true" during loading and remove it once content replaces the skeleton.
Reduced motion
The shimmer animation pauses or becomes subtle when prefers-reduced-motion: reduce is set; the static outline still conveys "loading".
Known caveats
Skeleton vs spinner. For short waits (< 1 s), a skeleton can feel slower than no placeholder. Use LoadingIndicator for brief operations and reserve skeletons for content-heavy loads.
Mismatched shapes. If a skeleton doesn't approximate the final content, the swap feels jarring. Match approximate heights and the number of lines so the layout doesn't jump when real data arrives.