|
| 1 | +# Guideline |
| 2 | + |
| 3 | +## Intro 👈🤖 |
| 4 | + |
| 5 | +The skeleton component provides visual loading placeholders that represent content structure while data loads, reducing perceived wait time. |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## Definition |
| 10 | + |
| 11 | +The skeleton component is a visual element used to indicate that content is loading. It provides a smooth user experience by temporarily replacing content with gray areas or animations simulating the visual structure of the content to come. |
| 12 | + |
| 13 | +--- |
| 14 | + |
| 15 | +## Best for 👈🤔 |
| 16 | + |
| 17 | +✅ Displaying loading states for container-based components like cards, tiles, and structured lists |
| 18 | + |
| 19 | +✅ Progressive page loading where content appears incrementally as data becomes available |
| 20 | + |
| 21 | +✅ Reducing perceived load time when fetching asynchronous data |
| 22 | + |
| 23 | +✅ Maintaining layout structure during initial page render to prevent cumulative layout shift |
| 24 | + |
| 25 | +✅ Loading states for data-driven content like tables, user profiles, and media galleries |
| 26 | + |
| 27 | +✅ Placeholder previews when visual layout is known ahead of time |
| 28 | + |
| 29 | +✅ Mobile and web applications where network latency affects content delivery |
| 30 | + |
| 31 | +✅ Streaming content interfaces where items load in batches |
| 32 | + |
| 33 | +✅ Dashboard widgets loading real-time data from multiple sources |
| 34 | + |
| 35 | +✅ E-commerce product listings during catalog fetch operations |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +## Anatomy 👈🤖 |
| 40 | + |
| 41 | +| # | Element | Purpose | Optional | |
| 42 | +|---|---------|---------|----------| |
| 43 | +| 1 | Background | Provides the base visual placeholder shape with subtle gray fill | N | |
| 44 | +| 2 | Shimmer/Gradient | Animated overlay creating horizontal wave effect to indicate active loading | Y | |
| 45 | +| 3 | Security margin | Transparent padding preventing large uniform surfaces when components stack | Y | |
| 46 | +| 4 | Container | Wrapper element defining skeleton dimensions and overflow behavior | N | |
| 47 | +| 5 | Shape variants | Different geometric forms (rectangle, circle, text) matching content types | N | |
| 48 | + |
| 49 | +--- |
| 50 | + |
| 51 | +## Boolean options |
| 52 | + |
| 53 | +**Security margin** Depending on the position of components in the Skeleton screen template, two variants are possible: |
| 54 | +• If a margin (spacing) is present between two or more components, apply the version "Security margin=False" to the affected components. |
| 55 | +• If no spacing is present between two or more components, apply the version "Security margin=True" to the affected components. |
| 56 | + |
| 57 | +The "Security margin=True" variant includes transparent padding (with 0% opacity) at the top and bottom of the skeleton component. This padding prevents the creation of excessively large uniform surfaces, maintaining a visually balanced and structured layout. |
| 58 | + |
| 59 | +--- |
| 60 | + |
| 61 | +## boolean_options_do_&_dont 👈🤔 |
| 62 | + |
| 63 | +✅ **Do:** Use security margin=True when stacking skeletons without spacing to maintain visual separation between loading elements. |
| 64 | +❌ **Don't:** Apply security margin=True when components already have spacing between them, as this creates unnecessary extra padding. |
| 65 | + |
| 66 | +✅ **Do:** Match the security margin setting consistently across all skeleton components within the same loading screen template. |
| 67 | +❌ **Don't:** Mix security margin variants inconsistently within a single loading view, creating an unbalanced visual appearance. |
| 68 | + |
| 69 | +✅ **Do:** Consider the final loaded content layout when deciding security margin settings to ensure smooth transition without layout shift. |
| 70 | +❌ **Don't:** Ignore the relationship between adjacent components when selecting security margin variants. |
| 71 | + |
| 72 | +✅ **Do:** Use security margin=False when components have defined spacing tokens applied between them in the design. |
| 73 | +❌ **Don't:** Use security margin=True as a default without evaluating the actual spacing context of your layout. |
| 74 | + |
| 75 | +✅ **Do:** Test both variants in context to verify the skeleton accurately represents the structure of the content being loaded. |
| 76 | +❌ **Don't:** Assume one security margin setting works universally across all skeleton implementations. |
| 77 | + |
| 78 | +--- |
| 79 | + |
| 80 | +# Specs |
| 81 | + |
| 82 | +## States |
| 83 | + |
| 84 | +🚧 Missing from source: States section in skeleton_overview.md |
| 85 | + |
| 86 | +--- |
| 87 | + |
| 88 | +## Layout and spacing |
| 89 | + |
| 90 | +🚧 Content to be added |
| 91 | + |
| 92 | +--- |
| 93 | + |
| 94 | +# Accessibility 👈🤖 |
| 95 | + |
| 96 | +## Accessibility intro |
| 97 | + |
| 98 | +The skeleton component must meet WCAG 2.2 Level AA standards by properly communicating loading states to all users, including those using assistive technologies. For comprehensive accessibility guidance, see the [Orange Unified Design System Accessibility Overview](https://unified-design-system.orange.com/472794e18/p/88ebab-accessibility-and-sustainability). |
| 99 | + |
| 100 | +--- |
| 101 | + |
| 102 | +## Accessibility Challenges |
| 103 | + |
| 104 | +Skeleton loaders present unique accessibility challenges because they are purely visual indicators that must communicate loading status to users who cannot see them. Screen readers need programmatic notification of loading states, and animations must respect user motion preferences. |
| 105 | + |
| 106 | +### Key Challenges |
| 107 | +- Conveying loading status to screen reader users who cannot perceive visual placeholders |
| 108 | +- Preventing animation from causing discomfort for users with vestibular disorders |
| 109 | +- Ensuring loading completion is announced when content replaces skeleton |
| 110 | +- Maintaining low contrast that indicates placeholder status without causing visibility issues |
| 111 | + |
| 112 | +### Critical Success Factors |
| 113 | +1. Implement `aria-busy="true"` on container elements during loading (WCAG 4.1.3) |
| 114 | +2. Provide visually hidden loading announcements via `role="status"` or `aria-live` regions |
| 115 | +3. Respect `prefers-reduced-motion` media query for shimmer animations |
| 116 | +4. Remove skeleton and update ARIA attributes when content loads |
| 117 | + |
| 118 | +--- |
| 119 | + |
| 120 | +## Design Requirements |
| 121 | + |
| 122 | +### Structure & Labels |
| 123 | +- [ ] **Container aria-busy**: Set `aria-busy="true"` on loading container, `false` when loaded ([Orange status messages](https://a11y-guidelines.orange.com/en/web/develop/dynamic-content/)) |
| 124 | +- [ ] **Loading announcement**: Include visually hidden text "Loading" within skeleton or via `aria-live` region |
| 125 | +- [ ] **Hide decorative shapes**: Apply `aria-hidden="true"` to skeleton visual shapes |
| 126 | + |
| 127 | +### Visual Design |
| 128 | +- [ ] **Reduced motion**: Disable shimmer animation when `prefers-reduced-motion: reduce` is set ([Orange animations](https://a11y-guidelines.orange.com/en/web/design/animations/)) |
| 129 | +- [ ] **Visible placeholder**: Background color provides sufficient visibility on page background |
| 130 | +- [ ] **No focus trap**: Skeleton elements do not receive keyboard focus |
| 131 | + |
| 132 | +### Content |
| 133 | +- [ ] **Completion announcement**: Announce "Content loaded" or equivalent when loading completes |
| 134 | +- [ ] **Timeout handling**: Provide fallback messaging if loading exceeds 5 seconds |
| 135 | + |
| 136 | +--- |
| 137 | + |
| 138 | +## Testing Checklist |
| 139 | + |
| 140 | +### Screen Reader Testing |
| 141 | +- [ ] Test with NVDA (Windows), JAWS (Windows), VoiceOver (macOS/iOS), TalkBack (Android) |
| 142 | +- [ ] Verify "loading" announced on entry, "loaded" announced on completion, no skeleton shapes read |
| 143 | + |
| 144 | +### Keyboard Testing |
| 145 | +- [ ] Skeleton shapes are not focusable, focus moves naturally to loaded content |
| 146 | +- [ ] No keyboard traps occur during loading state transitions |
| 147 | + |
| 148 | +### Motion Testing |
| 149 | +- [ ] Shimmer animation stops when `prefers-reduced-motion: reduce` is enabled in OS settings |
| 150 | + |
| 151 | +Resources: [Orange Accessibility Testing Guide](https://a11y-guidelines.orange.com/en/web/test/) |
| 152 | + |
| 153 | +--- |
| 154 | + |
| 155 | +## Key WCAG Criteria |
| 156 | + |
| 157 | +- **1.4.11 Non-text Contrast** (AA): Skeleton shapes visible against background (≥3:1 not strictly required for loading indicators per WCAG) |
| 158 | +- **2.2.2 Pause, Stop, Hide** (A): Shimmer animation can be paused or respects reduced motion preference |
| 159 | +- **2.3.1 Three Flashes or Below Threshold** (A): Shimmer animation does not flash more than three times per second |
| 160 | +- **4.1.2 Name, Role, Value** (A): Loading state communicated via ARIA attributes to assistive technology |
| 161 | +- **4.1.3 Status Messages** (AA): Loading status announced without receiving focus via live regions |
| 162 | + |
| 163 | +For complete reference: [Orange Accessibility Guidelines - Components](https://a11y-guidelines.orange.com/en/web/components-examples/) |
| 164 | + |
| 165 | +--- |
| 166 | + |
| 167 | +## Additional Resources |
| 168 | + |
| 169 | +- [Orange Accessibility Guidelines - Dynamic Content](https://a11y-guidelines.orange.com/en/web/develop/dynamic-content/) |
| 170 | +- [More Accessible Skeletons - Adrian Roselli](https://adrianroselli.com/2020/11/more-accessible-skeletons.html) |
| 171 | +- [WCAG 2.2 Understanding Status Messages](https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html) |
| 172 | +- [Carbon Design System - Loading Pattern](https://carbondesignsystem.com/patterns/loading-pattern/) |
| 173 | + |
| 174 | +--- |
| 175 | + |
| 176 | +# Changelog |
| 177 | + |
| 178 | +| Date | Number | Notes | Designer | |
| 179 | +|------|--------|-------|----------| |
| 180 | +| Dec 5, 2024 | 1.0.0 | • Component creation | Maxime Tonnerre | |
0 commit comments