Skeleton list
canonReady-made loading body for listings: avatar circle, main line and a meta line, with aria-busy on the wrapper.
`.sk-card`/`.sk-kv` (kanban card and drawer composed skeletons) were unused and removed as dead code in acrm !4058 (28 Sep 2026); `SkeletonList` only ever emitted `.sk-task`.
Used in 69 files · 51 areas · 95× — components/accounting, components/agent-desk, components/ai-employees, components/calendar, components/company, components/deal …
Keyboard
- Nothing inside is focusable; there is no tab stop between the top bar and whatever follows the list.
- While the skeleton is up, the region the user was in has no interactive content — a host that took focus away must give it back when the rows arrive.
ARIA
- The wrapper sets
aria-busy="true", which is the one signal the component makes. It tells assistive technology that this region is being updated rather than that it is empty. - No
role="status"and no live region: a first load is a navigation the user initiated, not an event to interrupt them with. - The rows carry no roles — they are not list items and must not be announced as such, because they stand for nothing yet.
- When the data lands, remove the whole block. Leaving
aria-busy="true"on a filled region is worse than never setting it.
Focus
- No focusable descendants and no focus ring.
Contrast
- The bars and circles come from the surface scale and are intentionally low-contrast; they represent absent content, so AA text thresholds do not apply.
Known limits
- The shimmer ignores
prefers-reduced-motion. - The switch from busy to ready is not announced; a screen-reader user has to go back and re-read the region to notice the rows.
aria-busylives on the wrapper only — a host that renders the skeleton next to real content, rather than in place of it, gives an inaccurate picture of what is loading.
Source: docs/loading/skeleton-list.a11y.md · GitLab