AL
- ·
Can we move the call to Thursday? The team needs a day to go through the numbers.
A placeholder for content that is still loading. It keeps the shape of what it replaces and shimmers with the same light sweep as Marker’s text.
import {
Skeleton,
SkeletonGroup,
} from "@o/pipeline/experimental/components/skeleton";
Skeleton only the content that is loading. Render containers for real straight away, such as a Card, a table’s frame and headers, or a list’s frame, and let only the content inside them show as placeholders. Layout components take no skeleton prop. Neither do on-demand popups whose content is already on screen, such as Find, Menu and Tooltip: they open over a loaded page, so there is nothing for a placeholder to stand in for.
Note
With reduced motion, and in Firefox, the fill doesn’t shimmer.
skeletonPass skeleton to a component instead of swapping it for a hand-made placeholder, so its box keeps its shape when the content arrives. The swap is instant, with no fade. These components take it:
Table.CellAvatar.RootGlyphCheckbox and Checkbox.RootButton and IconButtonBadgeCountChip.RootKbd and KbdComboIndicatorFeed.EventComment.MessageAuthor, Comment.MessageMetaListItem and Comment.MessageBodySelect.TriggerChoice.TriggerDatePickerPopoverSwitchToggleGroup.Root<Table.Cell skeleton={loading}>{company.name}</Table.Cell>
A skeleton is inert: nothing in it takes focus or reaches assistive technology.
| Company | Stage |
|---|---|
| AAutodesk | In review |
| Northwind Traders | Active |
SkeletonUse Skeleton for content that no component stands in for, such as a row’s text or a whole card. By default, it takes the size of what you pass it, without showing it:
width. skeletonLineWidth(row, column) varies the width by position and returns the same value on every render.A width or className overrides the default size.
<Skeleton width={skeletonLineWidth(row)} />
<Skeleton shape="block" className="h-55" />
shape="block" fills its container’s width and takes its height from its content or its className. Use one block for a whole card, such as a chart, until it has leaves of its own.
shape="lines" does for any content what a line does for text: the content lays out unseen in the element its render and className give, and each line it sets gets a bar. Feed.Event uses it, so an event’s text parts read as one run of text.
SkeletonTextSkeletonText shows its text as a placeholder while its group is loading, or when you set its skeleton prop. Otherwise it renders the text as it is. Use it for text inside your own markup, such as the name beside an avatar.
<Table.Cell skeleton={loading}>
<Avatar.Root>…</Avatar.Root>
<SkeletonText>{company.name}</SkeletonText>
</Table.Cell>
SkeletonContentSkeletonContent marks its content as placeholders without adding an element. Components inside it draw their own skeletons, and plain text becomes lines. Table.Cell uses it, so a cell with an avatar and a name shows the avatar’s shape and a bar for the name.
SkeletonGroupSkeletonGroup sets skeleton for every component inside it, so a whole block loads at once. For text with no component of its own, read the group with useSkeleton().
<SkeletonGroup loading={loading}>
<EntityList items={items} />
</SkeletonGroup>
The innermost group decides which components draw a skeleton, and a component’s own skeleton prop overrides any group. A finished group inside a loading one shows its content, but you can’t use it until the outer group finishes too.
SkeletonStatusSkeletonStatus speaks for the loading groups inside it, for a region whose parts load separately, such as a card whose sections each sync on their own. While any of those groups is showing, it announces one status, its label, and the groups stay quiet. It adds no element, and it changes nothing else: each group still waits and paints as it would on its own, and the content around them stays real and usable.
<SkeletonStatus label="Loading workstream">
<Header workstream={workstream} />
<SkeletonGroup loading={!progress}>…</SkeletonGroup>
<SkeletonGroup loading={!signals}>…</SkeletonGroup>
</SkeletonStatus>
Each block exports a skeleton built from the real block inside a SkeletonGroup, so every place that waits on it shows the same shape:
TableSkeleton and TableSkeletonRowEntityListSkeletonTaskListSkeletonSeriesChartSkeleton| Deal | Company | Stage | Amount |
|---|---|---|---|
data-skeleton attributedata-skeleton marks the element that paints a skeleton. skeleton.css hides what’s inside that element and paints the shimmering fill in its box, radius and all.
Style a component’s own skeleton state with the data-skeleton: variant, such as Glyph’s softer radius. The attribute always comes with inert.
A component gets both from useSkeleton(). The hook resolves the component’s skeleton prop against the nearest group, and returns props to spread or merge onto the element:
const { skeleton, props } = useSkeleton(skeletonProp);
return <span {...props}>…</span>;
Note
A component’s other data attributes come from useRender state. data-skeleton comes from these props instead, so every component sets it the same way, whether it’s built on useRender or not.
When the box that paints the skeleton isn’t the element that must be inert, the component sets the two separately from skeleton:
Checkbox: paints its inner box and makes its root inert, so the frame around the box stays clearButton: has no box to stand in for, so a bar over its text and icons paints the skeleton, and the button itself is only inertTable.Cell: is only inert, and the content inside it draws its own skeletonsOnly the outermost loading group announces anything. It sets aria-busy and announces one status, its label (“Loading…” by default). Groups inside it stay quiet. Inside a SkeletonStatus, the status speaks for them instead.
A loading group is inert as a whole, so you can’t use anything in it, and assistive technology hears only its status. The status sits beside the group, not inside it. Links keep their hrefs.
The outermost group waits 150 ms before its skeletons show, so a fast load never flashes one. A group that takes over from a skeleton already on screen shows at once.