Background
- Description: Skeletons are loading indicators that take the approximate shape of the UI elements they are acting as a placeholder for.
- History: There are two main tasks and threads that should be taken into consideration when tackling the definition of this pattern: T280842: Define and add guidelines for adding skeleton/placeholder UI to the DSG and T266028: Add “Progress indicators” to DSG.
- Known use case(s): Skeleton loaders are currently used in production in the following scenarios: Within Growth's Newcomer homepage suggested edits modules (or cards), as loading indicators for images in Wikipedia articles (only in Minerva), as loading indicators for the main search's menu item thumbnails in Minerva.
- Considerations: This pattern should be approved by the design team before being introduced in our design system. Its place among other progress/loading indicators (T266028) and usage recommendations should also be properly defined.
Further details are available in the following product document.
User stories
- As a designer and developer, I want to be able to reuse a skeleton animation to visually indicate to users that UI content is loading.
Previous implementations
These artifacts are listed for historical context. The figma spec, linked below, is the source of truth for the new component.
Design style guide:n/a. Skeleton loader has been asked for originally in T280842. Points there became starting points here.OOUI:n/aVue:n/a- Growth: CSS skeleton loader T321675: NewImpact: Create skeleton loading state (see code)
The most relevant implementations of skeleton loaders are in MobileFrontend and Minerva skin (using the class .image-lazy-loaded), and GrowthExperiments project (.se-card-image.skeleton, .se-card-extract.skeleton, .se-card-pageviews.skeleton).
| Growth newcomer homepage | Image thumbnails on articles | Image thumbnails on search (Minerva) |
| T263040 Suggested edits module T321675 Impact module | ||
Open questions
- Skeleton size: Is it possible to make the skeleton size to adjust to the size of the element that it’s replacing (i.e., be 100% in height in width), or should we create different predefined skeleton sizes? (e.g. 16px, 24px, 40px height)
- @Volker_E 2026-04-27: tl;dr There should be a small set of primitives, "consumer-composed". The CdxSkeletonComponent to come with shape prop with rectangle as default, line as possible 2nd on MVP, and further down in development circle could be another value. rectangle for all imagery loading states, line additional for text row loading. height with sensible default per shape, width as filling container default.
- Skeleton color: Do we need a lighter version of the skeleton to make it work if combined with darker backgrounds (see example)? e.g. frameless tabs, which are using the same gray tone as the skeleton. (Note 2026-04-28: This old open question might be solved thanks to Codex's compatibility with dark mode)
- Skeleton sequence: Could implementers control the sequence in which skeletons load? (e.g. via animation delay) Sh/could this be a prop?
Codex implementation
- Composition model:
- 1. skeleton prop on existing components
- Adding skeleton prop to existing components is the wrong direction for Codex:
- Every current and future component that needs a skeleton state gets more complex API surface
- Skeleton is a rare loading state; it should not pollute CdxCard, CdxThumbnail, etc.
- Skeleton layouts often represent partial loading (just the image, not the whole card) - a per-component prop cannot express that
- Adding skeleton prop to existing components is the wrong direction for Codex:
- 2. Per-component companions (CdxCardSkeleton)
- have the same maintenance problem and cause component explosion.
- 1. skeleton prop on existing components
therefore
- 3. a small set of shape primitives, consumer-composed
- Accessibility measurements
- Must-have: The visual skeleton element is aria-hidden="true" (decorative)
- Nice-to-have: The component automatically renders a visually-hidden <span role="status"> adjacent to it, with a default i18n'd label (e.g. "Loading", overridable via prop)
Component task owners
- Designer: @Sarai-WMDE
- Developer: add the main developer's name
Design spec
Stage 1: Minimum viable product (MVP)
MVP includes basic layout, default states, and most important functionality.
Acceptance criteria
- Determine what MVP includes for this component and document this in a subtask. Assign task to designer.
- Design MVP.
- Get approval by Product design team
- Once complete design MVP, assign task to developer.
- Implement MVP
Stage 2: Additional states, features, and variants
Acceptance criteria
- Document design and implementation of additional states and features in individual subtasks
- Complete each additional state/feature subtask
Stage 3: Refinement
Acceptance criteria
- Finalize docs: open and complete a subtask for any additional demos that need to be added or documentation that needs work
- Update loading guidelines added in T377434 with relevant information about Skeleton loaders
- Meet accessibility standards: open and complete a subtask for any necessary accessibility improvements
- Meet internationalization standards: open and complete a subtask to fix any i18n bugs
- Complete testing: open and complete a subtask for any additional unit or functional tests that are needed









