|
| 1 | +# Accessibility conformance report |
| 2 | + |
| 3 | +<p class="description">How Material UI components conform to WCAG 2.2 Level A and AA, reported in VPAT terms for procurement and accessibility review.</p> |
| 4 | + |
| 5 | +:::warning |
| 6 | +**Draft — partial coverage.** This report covers the 12 components assessed so far, not the whole library. It has not been reviewed by an external auditor, and no assistive-technology testing has been performed yet. See [Scope and limitations](#scope-and-limitations) before relying on it for a procurement decision. |
| 7 | +::: |
| 8 | + |
| 9 | +## About this report |
| 10 | + |
| 11 | +This is a Voluntary Product Accessibility Template (VPAT®) style report: it states, criterion by criterion, how far Material UI meets the [Web Content Accessibility Guidelines 2.2](https://www.w3.org/TR/WCAG22/) at Levels A and AA, using the conformance vocabulary defined by the [Information Technology Industry Council](https://www.itic.org/policy/accessibility/vpat). |
| 12 | + |
| 13 | +It is generated from the per-component conformance reports kept next to the source code, at `packages/mui-material/src/<Component>/accessibility.md`. Each of those rates its component against every applicable success criterion, records the reasoning, and gives the manual steps needed to re-verify the result. Nothing in this page is asserted without a corresponding component report behind it. |
| 14 | + |
| 15 | +### Product information |
| 16 | + |
| 17 | +| Field | Value | |
| 18 | +| :---- | :---- | |
| 19 | +| Product | Material UI (`@mui/material`) | |
| 20 | +| Product type | React component library (software) | |
| 21 | +| Version assessed | See the [releases page](https://github.com/mui/material-ui/releases) for the current version; results track the `master` branch | |
| 22 | +| Vendor | MUI | |
| 23 | +| Standards applied | WCAG 2.2 Level A and AA | |
| 24 | +| Report type | Self-assessment, published as source-controlled documentation | |
| 25 | + |
| 26 | +### Evaluation methods |
| 27 | + |
| 28 | +Conformance was determined by combining three methods, recorded per criterion in the component reports: |
| 29 | + |
| 30 | +- **⚙️ Automated.** [axe-core](https://github.com/dequelabs/axe-core) runs against the documentation demos inside the Playwright visual-regression suite, plus deterministic unit tests for behaviours axe cannot see (keyboard operation, focus order, pointer cancellation, accessible naming). Results are committed to the repository as `docs/data/material/components/<slug>/<slug>.a11y.json` and checked in CI, so a regression fails the build. |
| 31 | +- **🔁 Hybrid.** Automation catches regressions but human judgement is still needed to confirm the result. |
| 32 | +- **🔍 Manual.** Source review and human judgement. Each such criterion carries written test steps and an explicit pass condition so the assessment can be reproduced. |
| 33 | + |
| 34 | +:::warning |
| 35 | +**No assistive-technology testing has been performed.** Results are based on source review, automated checks, and manual keyboard testing. Screen-reader passes (NVDA, JAWS, VoiceOver) are planned but not yet done, so no claim is made about behaviour in specific assistive technologies. |
| 36 | +::: |
| 37 | + |
| 38 | +## How to read the ratings |
| 39 | + |
| 40 | +### Conformance |
| 41 | + |
| 42 | +| Symbol | Term | Meaning | |
| 43 | +| :----- | :--- | :------ | |
| 44 | +| ✅ | Supports | Met, with no known defects. | |
| 45 | +| ⚠️ | Partially Supports | Some functionality does not meet the criterion. | |
| 46 | +| ❌ | Does Not Support | Most functionality does not meet the criterion. | |
| 47 | +| ➖ | Not Applicable | The criterion does not apply to this component. | |
| 48 | + |
| 49 | +A criterion is **flagged** (🚩) when its rating was assessed from the source but is not yet confirmed by a test or a recorded review. **The flag is about strength of evidence, not about conformance** — a flagged ✅ is not a suspected defect, it is a result that has not yet been independently re-verified. |
| 50 | + |
| 51 | +### Who is responsible |
| 52 | + |
| 53 | +A component library is not an application, and this distinction matters more here than in a typical VPAT. Many success criteria cannot be met by a component alone — they depend on the page it is placed in, the content passed to it, and the theme applied to it. Each criterion is therefore also marked with where responsibility sits: |
| 54 | + |
| 55 | +| Symbol | Term | Meaning | |
| 56 | +| :----- | :--- | :------ | |
| 57 | +| ● | Component | Material UI satisfies it on its own. | |
| 58 | +| ◐ | Shared | Satisfied when the component is used as documented. | |
| 59 | +| ○ | Author | Depends on your implementation and the surrounding content. | |
| 60 | + |
| 61 | +:::info |
| 62 | +An application built with Material UI is not automatically accessible. Material UI supplies accessible building blocks; meeting WCAG for a finished product remains the responsibility of the team building it. The per-component reports state exactly which criteria fall to you. |
| 63 | +::: |
| 64 | + |
| 65 | +## Summary |
| 66 | + |
| 67 | +Across the 12 components assessed, against WCAG 2.2 Levels A and AA: |
| 68 | + |
| 69 | +| Result | Criteria ratings | |
| 70 | +| :----- | :--------------- | |
| 71 | +| ✅ Supports | 206 | |
| 72 | +| ⚠️ Partially Supports | 24 | |
| 73 | +| ❌ Does Not Support | 0 | |
| 74 | +| ➖ Not Applicable | 387 | |
| 75 | + |
| 76 | +**No component records a ❌ Does Not Support rating for any Level A or AA criterion.** |
| 77 | + |
| 78 | +Rolled up to the library level — where a criterion takes the worst rating any assessed component receives — 32 success criteria are exercised by at least one component: |
| 79 | + |
| 80 | +| Result | Success criteria | |
| 81 | +| :----- | :--------------- | |
| 82 | +| ✅ Supports | 25 | |
| 83 | +| ⚠️ Partially Supports | 7 | |
| 84 | +| ❌ Does Not Support | 0 | |
| 85 | + |
| 86 | +The remaining Level A and AA criteria are Not Applicable to every component assessed so far. They apply at the page or application level — for example [1.2.x Time-based Media](https://www.w3.org/WAI/WCAG22/Understanding/), [2.4.1 Bypass Blocks](https://www.w3.org/WAI/WCAG22/Understanding/bypass-blocks), [3.1.1 Language of Page](https://www.w3.org/WAI/WCAG22/Understanding/language-of-page) — and are the responsibility of the application. |
| 87 | + |
| 88 | +### Per-component results |
| 89 | + |
| 90 | +| Component | ✅ Supports | ⚠️ Partially Supports | ❌ Does Not Support | ➖ Not Applicable | |
| 91 | +| :-------- | :---------- | :-------------------- | :------------------ | :---------------- | |
| 92 | +| Accordion | 19 | 0 | 0 | 31 | |
| 93 | +| AccordionSummary | 23 | 1 | 0 | 31 | |
| 94 | +| Avatar | 9 | 2 | 0 | 44 | |
| 95 | +| Button | 23 | 4 | 0 | 28 | |
| 96 | +| Checkbox | 22 | 3 | 0 | 30 | |
| 97 | +| LinearProgress | 8 | 3 | 0 | 44 | |
| 98 | +| Radio | 23 | 2 | 0 | 30 | |
| 99 | +| RadioGroup | 7 | 0 | 0 | 30 | |
| 100 | +| Switch | 23 | 2 | 0 | 30 | |
| 101 | +| TextField | 25 | 3 | 0 | 27 | |
| 102 | +| ToggleButton | 20 | 4 | 0 | 31 | |
| 103 | +| ToggleButtonGroup | 4 | 0 | 0 | 31 | |
| 104 | + |
| 105 | +Container components (Accordion, RadioGroup, ToggleButtonGroup) defer item-level criteria to the component they contain, so their totals are smaller by design. |
| 106 | + |
| 107 | +## WCAG 2.2 report |
| 108 | + |
| 109 | +### Table 1: Success criteria, Level A |
| 110 | + |
| 111 | +| Criterion | Conformance | Remarks | |
| 112 | +| :-------- | :---------- | :------ | |
| 113 | +| 1.1.1 Non-text Content | ✅ Supports | Decorative icons are hidden from assistive technology; components that need a name accept one. | |
| 114 | +| 1.3.1 Info and Relationships | ✅ Supports | Native semantics and ARIA relationships are set by the components. | |
| 115 | +| 1.3.2 Meaningful Sequence | 🚩 ✅ Supports | Slots render in DOM order. Reading order across several controls is set by your layout. | |
| 116 | +| 1.3.3 Sensory Characteristics | 🚩 ✅ Supports | Components can be identified by name. Instructions in your content must not rely on shape, colour, or position alone. | |
| 117 | +| 1.4.1 Use of Color | 🚩 ⚠️ Partially Supports | Toggle Button: for the colour variants, selected and unselected labels are near-identical in grayscale, so the pressed state is conveyed largely by hue. | |
| 118 | +| 2.1.1 Keyboard | ✅ Supports | All interactive components are operable by keyboard; verified by automated tests. | |
| 119 | +| 2.1.2 No Keyboard Trap | ✅ Supports | Focus can always enter and leave; verified by automated tests. | |
| 120 | +| 2.2.2 Pause, Stop, Hide | 🚩 ⚠️ Partially Supports | LinearProgress: the `indeterminate`, `query`, and `buffer` variants animate indefinitely with no built-in pause, stop, or hide control. | |
| 121 | +| 2.3.1 Three Flashes or Below Threshold | 🚩 ✅ Supports | No component flashes more than three times per second. | |
| 122 | +| 2.4.3 Focus Order | ✅ Supports | Components are a single tab stop in DOM order, with no positive `tabIndex`; disabled controls leave the tab order. | |
| 123 | +| 2.4.4 Link Purpose (In Context) | ✅ Supports | Link text and accessible names are author-supplied and exposed unchanged. | |
| 124 | +| 2.5.2 Pointer Cancellation | 🚩 ✅ Supports | Activation happens on release over the target; releasing away cancels it. | |
| 125 | +| 2.5.3 Label in Name | 🚩 ✅ Supports | The accessible name includes the visible label text. | |
| 126 | +| 3.2.1 On Focus | ✅ Supports | Moving focus to a component does not activate it or change context. | |
| 127 | +| 3.2.2 On Input | ✅ Supports | Changing a value does not automatically change context. | |
| 128 | +| 3.3.1 Error Identification | ✅ Supports | TextField's `error` state is exposed programmatically and associated with the field. | |
| 129 | +| 3.3.2 Labels or Instructions | 🚩 ✅ Supports | Labelling APIs are provided and documented; supplying the text is the author's job. | |
| 130 | +| 4.1.2 Name, Role, Value | ⚠️ Partially Supports | Checkbox: the `indeterminate` state sets `aria-checked="mixed"` on a native checkbox whose `checked` property is `false`, which ARIA in HTML disallows. Setting the native `indeterminate` property instead is the conforming fix. | |
| 131 | + |
| 132 | +### Table 2: Success criteria, Level AA |
| 133 | + |
| 134 | +| Criterion | Conformance | Remarks | |
| 135 | +| :-------- | :---------- | :------ | |
| 136 | +| 1.3.5 Identify Input Purpose | ✅ Supports | `autocomplete` and related attributes pass through to the native input. | |
| 137 | +| 1.4.3 Contrast (Minimum) | 🚩 ⚠️ Partially Supports | Default-theme shortfalls: `info` and `warning` contained Buttons; Avatar's default white-on-`grey[400]` (~1.9:1); TextField's placeholder (~2.55:1) and some focused labels; selected Toggle Button labels. | |
| 138 | +| 1.4.4 Resize Text | 🚩 ✅ Supports | Typography is set in `rem`/`em` and scales with zoom. A fixed-pixel container in your layout could still clip. | |
| 139 | +| 1.4.5 Images of Text | ✅ Supports | Labels are real text. | |
| 140 | +| 1.4.10 Reflow | 🚩 ✅ Supports | Components reflow and labels wrap; horizontal overflow at 320px comes from the surrounding layout. | |
| 141 | +| 1.4.11 Non-text Contrast | 🚩 ⚠️ Partially Supports | The most widespread gap. The default keyboard focus indicator is the ripple, and `disableRipple`/`disableFocusRipple` removes it entirely. Several default boundaries also fall below 3:1 — TextField's `outlined` resting border (~1.74:1), AccordionSummary's focus tint (~1.3:1), Switch's light-mode thumb and track (~1.8–2.7:1), LinearProgress's fill-versus-track (~2.7:1 for `primary`). | |
| 142 | +| 1.4.12 Text Spacing | 🚩 ✅ Supports | Content stays visible under the WCAG text-spacing overrides; covered by a dedicated regression test. | |
| 143 | +| 2.4.6 Headings and Labels | 🚩 ✅ Supports | Components expose the labels they are given; wording is the author's responsibility. | |
| 144 | +| 2.4.7 Focus Visible | 🚩 ⚠️ Partially Supports | Button, Checkbox, Radio, Switch, Toggle Button: `disableRipple`/`disableFocusRipple` removes the only keyboard focus indicator unless you style `.Mui-focusVisible` yourself. Toggle Button has no fallback indicator at all. | |
| 145 | +| 2.4.11 Focus Not Obscured (Minimum) | 🚩 ✅ Supports | Components never obscure themselves; sticky headers and overlays in your layout can. | |
| 146 | +| 2.5.8 Target Size (Minimum) | ✅ Supports | Default sizes meet the 24×24 CSS-pixel minimum; verified by axe. | |
| 147 | +| 3.2.4 Consistent Identification | 🚩 ✅ Supports | One stable accessible name per set of props. Cross-page consistency is the author's responsibility. | |
| 148 | +| 3.3.3 Error Suggestion | ✅ Supports | Helper text is associated with the field; the suggestion text is author-supplied. | |
| 149 | +| 4.1.3 Status Messages | 🚩 ⚠️ Partially Supports | No live regions are added automatically: Button's `loading` state, TextField's dynamically shown error, and LinearProgress value changes may go unannounced. Add an `aria-live` region in your application. | |
| 150 | + |
| 151 | +## Known gaps and how to work around them |
| 152 | + |
| 153 | +Four issues account for almost every ⚠️ rating. Three are properties of the **default theme** rather than of the components' structure, which means a theme can resolve them today. |
| 154 | + |
| 155 | +### 1. The focus indicator is the ripple |
| 156 | + |
| 157 | +Affects **1.4.11** and **2.4.7** on Button, Checkbox, Radio, Switch, and Toggle Button. Setting `disableRipple` or `disableFocusRipple` — including globally via `MuiButtonBase` default props — removes the only visible keyboard focus indicator. |
| 158 | + |
| 159 | +**Workaround.** If you disable the ripple, restore an indicator in your theme: |
| 160 | + |
| 161 | +```js |
| 162 | +const theme = createTheme({ |
| 163 | + components: { |
| 164 | + MuiButtonBase: { |
| 165 | + styleOverrides: { |
| 166 | + root: { |
| 167 | + '&.Mui-focusVisible': { |
| 168 | + outline: '2px solid currentColor', |
| 169 | + outlineOffset: 2, |
| 170 | + }, |
| 171 | + }, |
| 172 | + }, |
| 173 | + }, |
| 174 | + }, |
| 175 | +}); |
| 176 | +``` |
| 177 | + |
| 178 | +### 2. Some default palette colours fall short of contrast minimums |
| 179 | + |
| 180 | +Affects **1.4.3** and **1.4.11**. The shortfalls are listed in Table 1 and Table 2 above and, per component, in the linked reports. |
| 181 | + |
| 182 | +**Workaround.** Override the affected palette entries, or avoid the affected variants for text-bearing UI. Contrast is a theme decision, so a compliant palette resolves this without changing component code. |
| 183 | + |
| 184 | +### 3. Dynamic state changes are not announced |
| 185 | + |
| 186 | +Affects **4.1.3** on Button, LinearProgress, and TextField. |
| 187 | + |
| 188 | +**Workaround.** Render your own `aria-live` region alongside the component when a state change needs announcing — for example a polite live region reporting upload progress next to a `LinearProgress`. |
| 189 | + |
| 190 | +### 4. Indefinite animation cannot be paused |
| 191 | + |
| 192 | +Affects **2.2.2** on LinearProgress's `indeterminate`, `query`, and `buffer` variants. |
| 193 | + |
| 194 | +**Workaround.** Only show an indeterminate progress bar while an operation is genuinely in flight, and remove it when the operation finishes. Material UI also honours `prefers-reduced-motion`. |
| 195 | + |
| 196 | +### One genuine defect |
| 197 | + |
| 198 | +Checkbox's `indeterminate` state (**4.1.2**) is a real bug rather than a theme or integration issue, and is tracked for a fix. |
| 199 | + |
| 200 | +## Scope and limitations |
| 201 | + |
| 202 | +:::warning |
| 203 | +Read this section before citing the report. |
| 204 | +::: |
| 205 | + |
| 206 | +- **Component coverage is partial.** 12 components are assessed. Widely used components including Select, Autocomplete, Dialog, Menu, Table, Tabs, Slider, Tooltip, Snackbar, and Drawer are **not yet assessed**, and this report says nothing about them. Components onboard incrementally. |
| 207 | +- **No assistive-technology testing.** No screen-reader passes have been performed. Criteria that depend on how a specific assistive technology behaves are assessed from the exposed accessibility tree, not from observed behaviour. |
| 208 | +- **Level AAA is out of scope**, as it is for a standard VPAT. |
| 209 | +- **Components are rated in isolation.** Each is assessed as rendered with default props and the default theme. Customisation, composition, and your surrounding page can change the result — which is what the ● / ◐ / ○ responsibility marks are for. |
| 210 | +- **Evidence strength varies.** 75 of the 230 criterion ratings are flagged as assessed-from-source but not yet re-verified by a test or recorded review. |
| 211 | +- **This is a self-assessment.** It has not been audited by an independent third party. |
| 212 | +- **Section 508 and EN 301 549 chapters are not yet included.** The WCAG tables above supply the substance those chapters incorporate by reference, but the chapter-by-chapter mapping — including Functional Performance Criteria, software requirements, and support-documentation requirements — has not been written. |
| 213 | + |
| 214 | +## Per-component reports |
| 215 | + |
| 216 | +Full reasoning, responsibility marks, and reproducible manual test steps live with the source: |
| 217 | + |
| 218 | +- [Reports index](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/accessibility.md) |
| 219 | +- [Accordion](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Accordion/accessibility.md) · [AccordionSummary](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/AccordionSummary/accessibility.md) |
| 220 | +- [Avatar](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Avatar/accessibility.md) |
| 221 | +- [Button](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Button/accessibility.md) |
| 222 | +- [Checkbox](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Checkbox/accessibility.md) |
| 223 | +- [LinearProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/LinearProgress/accessibility.md) |
| 224 | +- [Radio](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Radio/accessibility.md) · [RadioGroup](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/RadioGroup/accessibility.md) |
| 225 | +- [Switch](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Switch/accessibility.md) |
| 226 | +- [TextField](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/TextField/accessibility.md) |
| 227 | +- [ToggleButton](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/ToggleButton/accessibility.md) · [ToggleButtonGroup](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/ToggleButtonGroup/accessibility.md) |
| 228 | + |
| 229 | +## Feedback |
| 230 | + |
| 231 | +Accessibility defects are treated as bugs. Report them on [GitHub](https://github.com/mui/material-ui/issues/new/choose) with the component, the success criterion, and steps to reproduce. |
0 commit comments