Skeleton (loading placeholder)
components specs/components/skeleton.kmd
Skeleton placeholder primitives — block / line / circle / image — that mirror the final content shape during load. Reduces perceived load time and avoids cumulative layout shift on content swap. Modeled after Cedar (REI), Material 3, Polaris, Carbon.
Quando esta spec se aplica
Triggers primários
- Show loading state for any async content surface
Todos os triggers
- Replace a generic spinner with a content-shape placeholder
- Avoid CLS on async content render
Corpo da especificação
Component — Skeleton
Status: v0.1.0 — Draft.
R1 — Primitives
| Primitive | Default size | Use for |
|---|---|---|
KoderSkeletonBlock | configurable W×H, rounded --kdr-radius-sm | Cards, images, panels |
KoderSkeletonLine | full width × --kdr-fs-base height | Single line of text |
KoderSkeletonCircle | configurable radius | Avatars, status dots |
KoderSkeletonImage | configurable W×H, aspect-ratio preserved | Image slots |
Composers assemble these into placeholders mirroring the final layout (e.g., card skeleton = Image on top + 2 Lines + Block button).
R2 — Animation
- Default: subtle shimmer — linear gradient sweep across the surface, 1.5s loop.
prefers-reduced-motion: reduce: static pulse (opacity 0.6 → 1.0 → 0.6, 2s loop). NO sweep.prefers-reduced-motion: no-preference+ battery saver / Data saver detected: also fall back to static pulse.
R3 — Shape mirroring
The skeleton MUST replace the final content's bounding box at the same dimensions. Acceptance: when content arrives and the skeleton is removed, NO layout shift on the surrounding page (CLS contribution = 0).
Anti-pattern: spinner-in-a-fixed-box → content fills box. That's NOT a skeleton; that's a spinner.
R4 — Accessibility
- Surface wrapping the skeleton primitives carries
aria-busy="true"andaria-label="Loading"(translatable perspecs/i18n/contract.kmd). - Once content swaps in,
aria-busy="false"andaria-labelis removed. - Live-region MAY announce "Loading complete" on swap (per consumer choice; not mandated).
R5 — Color
- Default light:
--kdr-surface-2for base +--kdr-surfacefor highlight. - Default dark: same tokens (which already swap per theme).
- High-contrast /
forced-colorsmedia: skeleton usesCanvasandCanvasTextsystem colors with a 1px border.
R6 — Composer pattern
For common shapes, KDS ships composer presets (in koder_kit / koder_web_kit):
KoderSkeletonCardKoderSkeletonListRowKoderSkeletonTableRow(consumed by data-table empty/loading perspecs/components/data-table.kmdR12)KoderSkeletonAvatar
R7 — OUIA
Per specs/testing/ouia-test-hooks.kmd:
data-ouia-component-type="Skeleton"data-ouia-safe="false"always (skeleton IS the not-ready state).- The surface wrapping the skeleton ALSO carries the OUIA attrs of the eventual real component, with
data-ouia-safe="false"until swap.
Não-escopo
- Pre-fetched-content swap-in transitions (separate motion ticket).
- Server-rendered skeletons (SSR) — out of v0; renders on client mount.
Referências
specs/patterns/empty-state.kmdspecs/themes/verge.kmdspecs/components/data-table.kmd