Skip to content

Skeleton

P-10 · Primitives · Primitives

All elements · Skeleton on the Primitives page

Last checked 2026-10-22 · Awaiting approval · Accessibility tests

Copies the bun run a11y:approve command for Skeleton.

Skeleton

P-10WCAG 2.2 AA · Passed #437
Axis Values
data-shape text · rect · circle
style width/height geometry only; always aria-hidden
A loading list row and card

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__skeleton does.
  • 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

Do
  • 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
  • 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-motion cuts 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-100 and -200 and 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

WCAG 2.2 AA · Passed

Passed the gate (run 358b316 on 2026-10-22): no finding in any theme. Awaiting a person’s approval of the checklist below.

Skeleton test checklist
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.

Skeleton package
Source css/classic/primitives/behavior.css
Specimens also use Box · Card · Chip · Icon · Table · Text · Toolbar
Sprites sprites/icons.svg
React Not yet available: the React binding has not started.

Latest updates

No recorded changes yet.

All release notes