Skeleton
Skeleton loaders indicate that content is loading by masking supported components in place or by rendering explicit placeholder blocks.
Import
import { UNSTABLE_Skeleton, SkeletonPrimitive, getSkeletonClassName, useSkeleton, useSkeletonClassName,} from "@cfa/react-core";Skeleton is currently exported as an unstable component while the API is refined through beta feedback.
Live Editor
Patterns
Skeleton supports two loading patterns: wrapped content with useSkeleton, and manual SkeletonPrimitive blocks.
Content masking
Wrap real layout and mock content in UNSTABLE_Skeleton. When isLoading is true, the wrapper sets aria-busy, applies inert, and provides loading context to descendants through useSkeleton(). Full inert behavior (blocking focus and interaction inside the shell) requires React 19; on React 17/18, aria-busy and skeleton masking still apply.
Supported components apply their own skeleton styles when they read that context. Use CFA components in the layout rather than raw HTML when you want masking.
Supported components
These components call useSkeleton() and apply skeleton styles when wrapped in a loading UNSTABLE_Skeleton:
AvatarButtonandLinkButtonCard.Subtitle,Card.Body, andCard.Media(Card.TitleviaHeading)HeadingLinkProgressBarTable.CellandTable.ColumnText
Primitive placeholders
Use SkeletonPrimitive when you need full control over the loading layout, or when the real component is not wired to useSkeleton. Set width, height, and borderRadius to match the content you are loading.
Custom components
Use useSkeletonClassName() in your own components to apply the shared mask classes from the nearest loading Skeleton:
import { cx } from "class-variance-authority";import { useSkeletonClassName } from "@cfa/react-core";
function MyWidget({ className, children, ...props }) { const skeletonClassName = useSkeletonClassName();
return ( <div {...props} className={cx(className, skeletonClassName)}> {children} </div> );}For text-shaped placeholders, pass { variant: "text" }. When nested icons or images should be hidden while loading, add { hideContent: true }.
const skeletonClassName = useSkeletonClassName({ variant: "text", hideContent: true });Examples
Profile
Table
Progress bar
Usage guidance
- Wrap real CFA components with placeholder content to preserve layout and spacing.
- Full
inertbehavior on the loading shell requires React 19. On React 17/18,aria-busyand skeleton masking still apply. - Raw HTML such as
<p>or<img>is not masked automatically. Use a wired component (Text,Card.Media, and so on) or composeSkeletonPrimitiveblocks instead. - Form controls (
Select,TextInput,Checkbox, and similar) are not masked. UseSkeletonPrimitivefor field-shaped placeholders, or leave fields out of the loading layout. - Compose multiple
SkeletonPrimitiveelements when you need custom rows or form-field layouts. Chipis exported from@cfa/react-core/serverand does not readuseSkeleton(). UseSkeletonPrimitivefor chip-shaped placeholders instead.