P-10 · Primitives · Primitives
All elements · Skeleton on the Primitives page
Last checked 2026-10-22 · Awaiting approval · Accessibility tests
Approve Skeleton
Approving as
| Axis | Values |
|---|---|
data-shape |
text · rect · circle |
style width/height |
geometry only; always aria-hidden |
Guidance
When to use
- Hold the place of list rows, cards or table cells while their data loads.
- Show the shape of a record header (avatar, name, metadata) before it arrives.
- Fill a nav section that is loading its saved searches, as
.qf-nav__skeletondoes. - Keep the layout stable so content does not jump when it loads.
When to consider something else
- When a task has measurable progress or runs longer than a few seconds, use Progress. See Progress.
- When loading finishes with no results, replace the skeletons with Empty. See EmptyState.
- When a single control is busy, show a spinning Icon in the control instead. See Icon.
Usability
- Match the shape and approximate size of the content that will replace it.
- Vary text widths so the placeholder reads as lines, not bars.
- Show a small, fixed number of rows rather than filling the screen.
- Replace skeletons with an error message if loading fails.
- Don't show skeletons for content that loads almost instantly.
- Don't put interactive controls or real text inside a skeleton.
Accessibility
Keyboard
No keyboard interaction of its own.
Roles and names
- Every skeleton carries
aria-hidden="true"; it is geometry only. -
The container that is loading carries
aria-busy="true", as the nav tree does, and drops it when content arrives. -
Tell screen reader users that loading started or finished with a status message, such as
role="status"text or the app's live region.
Focus
- Skeletons are never focusable. When content replaces them, focus stays where it was; do not move it unless the user asked for the load.
Other requirements
- Skeleton is purely visual and has no keyboard behavior.
-
The shimmer loops every 1.4s;
prefers-reduced-motioncuts it to a single near-instant run (2.3.3). It is a soft gradient and does not flash (2.3.1). - Placeholders are decorative and exempt from contrast, but must not be the only sign of loading for non-visual users (4.1.3).
-
Skeletons use
--qf-color-info-100and-200and must stay distinct from real disabled content.
Test your implementation too. This guidance covers the element as specified here. How a screen composes it (labels, order, announcements) still needs its own keyboard and screen reader check.
Accessibility tests
Passed the gate (run 358b316 on 2026-10-22): no finding in any theme. Awaiting a person’s approval of the checklist below.
| Area | Automated | A person checks |
|---|---|---|
| General | Passed | Color is never the only cue, text alternatives say the same thing as the graphic, and the element reads the same in the light and the dark theme. |
| Zoom | Passed | At 200% zoom, at 320 CSS pixels wide and with the WCAG text-spacing overrides, nothing is lost, clipped or overlapping. |
| Keyboard | Passed | Every row of the Keyboard table works, focus is always visible and never trapped, and the tab order follows the reading order. |
| Screen reader | Passed | With NVDA or JAWS on Windows and VoiceOver on macOS, names, roles and states are announced as Roles and names says, and changes are announced once. (3 items) |
Approving. When the checklist passes on the checked run, record it with
bun run a11y:approve -- skeleton --by "Your name" and commit
a11y/approvals.json with the rebuilt pages.
All test status
Package
Consumers link one stylesheet, css/classic/index.css, which includes every element. The
files below are where this element is defined.
Latest updates
No recorded changes yet.