How Material UI components conform to WCAG 2.2 Level A and AA, reported in VPAT terms for procurement and accessibility review.
:::warning
-**Draft — partial coverage.** This report covers the 13 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.
+**Draft — partial coverage.** This report covers only the components in the [component table](#conformance-by-component), 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.
:::
## About this report
@@ -43,6 +43,7 @@ Each row counts only the criteria that **apply** to that component; criteria tha
| [Button](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Button/accessibility.md) | 15 | 12 | 27 | 24 | 3 | 20/27 | 11 |
| [Checkbox](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Checkbox/accessibility.md) | 14 | 11 | 25 | 24 | 1 | 22/25 | 11 |
| [CircularProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/CircularProgress/accessibility.md) | 6 | 5 | 11 | 8 | 3 | 6/11 | 1 |
+| [FormLabel](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/FormLabel/accessibility.md) | 7 | 6 | 13 | 11 | 2 | 10/13 | 4 |
| [LinearProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/LinearProgress/accessibility.md) | 6 | 5 | 11 | 8 | 3 | 6/11 | 1 |
| [Radio](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Radio/accessibility.md) | 14 | 11 | 25 | 24 | 1 | 23/25 | 11 |
| [RadioGroup](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/RadioGroup/accessibility.md) | 6 | 1 | 7 | 7 | 0 | 4/7 | 2 |
@@ -57,7 +58,7 @@ Each row counts only the criteria that **apply** to that component; criteria tha
**No component records a ❌ Does Not Support rating for any Level A or AA criterion.**
-Rolled up to the library level, where each criterion takes the worst rating any assessed component receives, 32 success criteria are exercised: **27 Supports, 5 Partially Supports, 0 Does Not Support.**
+Rolled up to the library level, where each criterion takes the worst rating any assessed component receives, 32 success criteria are exercised: **26 Supports, 6 Partially Supports, 0 Does Not Support.**
@@ -80,17 +81,19 @@ An application built with Material UI is not automatically accessible. Material
## Known gaps
-Five issues account for every ⚠️ rating. Two of them can be fixed through the theme today.
+Each ⚠️ rating comes from one of the issues below. Some of them can be fixed through the theme today.
-| Gap | Criteria | Affected | Workaround |
-| :------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------- |
-| **By default, the keyboard focus indicator is the ripple or a background tint, with untested contrast** | [1.4.11 Non-text Contrast](https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html) | [AccordionSummary](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/AccordionSummary/accessibility.md) [Button](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Button/accessibility.md) [Checkbox](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Checkbox/accessibility.md) [Radio](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Radio/accessibility.md) [Switch](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Switch/accessibility.md) [ToggleButton](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/ToggleButton/accessibility.md) | Enable `focusVisible` in your theme — see below |
-| **Some default palette colors fall short of contrast minimums** | [1.4.3 Contrast (Minimum)](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html) [1.4.11 Non-text Contrast](https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html) | [Avatar](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Avatar/accessibility.md) [Button](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Button/accessibility.md) [CircularProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/CircularProgress/accessibility.md) (`warning` with `enableTrackSlot`) [LinearProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/LinearProgress/accessibility.md) [Switch](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Switch/accessibility.md) [TextField](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/TextField/accessibility.md) [ToggleButton](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/ToggleButton/accessibility.md) | Override the affected palette entries |
-| **The selected state of colored Toggle Buttons is conveyed almost entirely by hue** | [1.4.1 Use of Color](https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html) | [ToggleButton](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/ToggleButton/accessibility.md) (`primary`, `error`, `info`, `success`) | Add a non-color cue to the selected state, such as an icon |
-| **Dynamic state changes are not announced** | [4.1.3 Status Messages](https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html) | [Button](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Button/accessibility.md) (`loading`) [CircularProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/CircularProgress/accessibility.md) [LinearProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/LinearProgress/accessibility.md) [TextField](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/TextField/accessibility.md) (error) | Render your own `aria-live` region alongside |
-| **Indefinite animation cannot be paused** | [2.2.2 Pause, Stop, Hide](https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html) | [CircularProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/CircularProgress/accessibility.md) (`indeterminate`) [LinearProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/LinearProgress/accessibility.md) (`indeterminate`, `query`, `buffer`) | Show it only while an operation is in flight |
+| Gap | Criteria | Affected | Workaround |
+| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **By default, the keyboard focus indicator is the ripple or a background tint, with untested contrast** | [1.4.11 Non-text Contrast](https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html) | [AccordionSummary](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/AccordionSummary/accessibility.md) [Button](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Button/accessibility.md) [Checkbox](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Checkbox/accessibility.md) [Radio](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Radio/accessibility.md) [Switch](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Switch/accessibility.md) [ToggleButton](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/ToggleButton/accessibility.md) | Enable `focusVisible` in your theme — see below |
+| **Some default palette colors fall short of contrast minimums** | [1.4.3 Contrast (Minimum)](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html) [1.4.11 Non-text Contrast](https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html) | [Avatar](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Avatar/accessibility.md) [Button](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Button/accessibility.md) [CircularProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/CircularProgress/accessibility.md) (`warning` with `enableTrackSlot`) [FormLabel](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/FormLabel/accessibility.md) (focused `info`, `warning`) [LinearProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/LinearProgress/accessibility.md) [Switch](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Switch/accessibility.md) [TextField](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/TextField/accessibility.md) [ToggleButton](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/ToggleButton/accessibility.md) | Override the affected palette entries |
+| **In dark mode, the elevation overlay lowers the contrast of `error` text below 4.5:1 on a Paper with elevation 2 or more, such as a Menu or a Dialog** | [1.4.3 Contrast (Minimum)](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html) | [FormLabel](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/FormLabel/accessibility.md) [TextField](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/TextField/accessibility.md) | Set a lighter `error.main` for dark mode, or show error text on a surface with elevation 0 or 1 |
+| **The selected state of colored Toggle Buttons is conveyed almost entirely by hue** | [1.4.1 Use of Color](https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html) | [ToggleButton](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/ToggleButton/accessibility.md) (`primary`, `error`, `info`, `success`) | Add a non-color cue to the selected state, such as an icon |
+| **A required checkbox, radio, or switch group exposes no required state to assistive technology, because Checkbox, Radio, and Switch do not take `required` from FormControl and RadioGroup has no `required` prop** | [1.3.1 Info and Relationships](https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships.html) | [FormLabel](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/FormLabel/accessibility.md) (`required` group legend) | Set `aria-required` on a RadioGroup. Set `required` on a single Checkbox or Switch, or on its FormControlLabel, which forwards it to the control. For a checkbox group, state the requirement in the legend text |
+| **Dynamic state changes are not announced** | [4.1.3 Status Messages](https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html) | [Button](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Button/accessibility.md) (`loading`) [CircularProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/CircularProgress/accessibility.md) [LinearProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/LinearProgress/accessibility.md) [TextField](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/TextField/accessibility.md) (error) | Render your own `aria-live` region alongside |
+| **Indefinite animation cannot be paused** | [2.2.2 Pause, Stop, Hide](https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html) | [CircularProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/CircularProgress/accessibility.md) (`indeterminate`) [LinearProgress](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/LinearProgress/accessibility.md) (`indeterminate`, `query`, `buffer`) | Show it only while an operation is in flight |
@@ -106,7 +109,7 @@ const theme = createTheme({ focusVisible: true });
Read this section before citing the report.
:::
-- **Component coverage is partial.** 13 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.
+- **Component coverage is partial.** Only the components in the [component table](#conformance-by-component) 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.
- **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 behavior.
- **Level AAA is out of scope**, as it is for a standard VPAT.
- **Components are rated in isolation**, as rendered with default props and the default theme. Customization, composition, and your surrounding page can change the result.
diff --git a/docs/data/material/getting-started/accessibility/knownGaps.json b/docs/data/material/getting-started/accessibility/knownGaps.json
index 6062cc623e1f74..3e0aab528a7552 100644
--- a/docs/data/material/getting-started/accessibility/knownGaps.json
+++ b/docs/data/material/getting-started/accessibility/knownGaps.json
@@ -12,6 +12,7 @@
"Avatar",
"Button",
{ "component": "CircularProgress", "note": "`warning` with `enableTrackSlot`" },
+ { "component": "FormLabel", "note": "focused `info`, `warning`" },
"LinearProgress",
"Switch",
"TextField",
@@ -19,12 +20,24 @@
],
"workaround": "Override the affected palette entries"
},
+ {
+ "gap": "In dark mode, the elevation overlay lowers the contrast of `error` text below 4.5:1 on a Paper with elevation 2 or more, such as a Menu or a Dialog",
+ "criteria": ["1.4.3"],
+ "affected": ["FormLabel", "TextField"],
+ "workaround": "Set a lighter `error.main` for dark mode, or show error text on a surface with elevation 0 or 1"
+ },
{
"gap": "The selected state of colored Toggle Buttons is conveyed almost entirely by hue",
"criteria": ["1.4.1"],
"affected": [{ "component": "ToggleButton", "note": "`primary`, `error`, `info`, `success`" }],
"workaround": "Add a non-color cue to the selected state, such as an icon"
},
+ {
+ "gap": "A required checkbox, radio, or switch group exposes no required state to assistive technology, because Checkbox, Radio, and Switch do not take `required` from FormControl and RadioGroup has no `required` prop",
+ "criteria": ["1.3.1"],
+ "affected": [{ "component": "FormLabel", "note": "`required` group legend" }],
+ "workaround": "Set `aria-required` on a RadioGroup. Set `required` on a single Checkbox or Switch, or on its FormControlLabel, which forwards it to the control. For a checkbox group, state the requirement in the legend text"
+ },
{
"gap": "Dynamic state changes are not announced",
"criteria": ["4.1.3"],
diff --git a/docs/data/material/getting-started/accessibility/scorecard.json b/docs/data/material/getting-started/accessibility/scorecard.json
index 5602791ebcc2b5..18ce20f2476082 100644
--- a/docs/data/material/getting-started/accessibility/scorecard.json
+++ b/docs/data/material/getting-started/accessibility/scorecard.json
@@ -1,12 +1,12 @@
{
"standard": "WCAG 2.2 Level A and AA",
- "componentCount": 13,
+ "componentCount": 14,
"totals": {
"rated": 32,
- "supports": 27,
- "partiallySupports": 5,
+ "supports": 26,
+ "partiallySupports": 6,
"doesNotSupport": 0,
- "flagged": 13
+ "flagged": 14
},
"criteria": [
{
@@ -21,9 +21,9 @@
"number": "1.3.1",
"name": "Info and Relationships",
"level": "A",
- "conformance": "Supports",
- "flagged": false,
- "affected": []
+ "conformance": "Partially Supports",
+ "flagged": true,
+ "affected": ["FormLabel"]
},
{
"number": "1.3.2",
@@ -63,7 +63,7 @@
"level": "AA",
"conformance": "Partially Supports",
"flagged": true,
- "affected": ["Avatar", "Button", "TextField", "ToggleButton"]
+ "affected": ["Avatar", "Button", "FormLabel", "TextField", "ToggleButton"]
},
{
"number": "1.4.4",
@@ -1538,6 +1538,158 @@
"automated": 1
}
},
+ {
+ "component": "FormLabel",
+ "counts": {
+ "supports": 11,
+ "partiallySupports": 2,
+ "doesNotSupport": 0,
+ "notApplicable": 42,
+ "flagged": 3,
+ "rated": 13
+ },
+ "gaps": [
+ {
+ "number": "1.3.1",
+ "name": "Info and Relationships",
+ "conformance": "Partially Supports"
+ },
+ {
+ "number": "1.4.3",
+ "name": "Contrast (Minimum)",
+ "conformance": "Partially Supports"
+ }
+ ],
+ "criteria": [
+ {
+ "number": "1.3.1",
+ "name": "Info and Relationships",
+ "level": "A",
+ "conformance": "Partially Supports",
+ "responsibility": "Shared",
+ "group": "Hybrid",
+ "flagged": true
+ },
+ {
+ "number": "1.3.2",
+ "name": "Meaningful Sequence",
+ "level": "A",
+ "conformance": "Supports",
+ "responsibility": "Author",
+ "group": "Manual",
+ "flagged": false
+ },
+ {
+ "number": "1.3.3",
+ "name": "Sensory Characteristics",
+ "level": "A",
+ "conformance": "Supports",
+ "responsibility": "Author",
+ "group": "Manual",
+ "flagged": false
+ },
+ {
+ "number": "1.4.1",
+ "name": "Use of Color",
+ "level": "A",
+ "conformance": "Supports",
+ "responsibility": "Shared",
+ "group": "Hybrid",
+ "flagged": true
+ },
+ {
+ "number": "1.4.3",
+ "name": "Contrast (Minimum)",
+ "level": "AA",
+ "conformance": "Partially Supports",
+ "responsibility": "Component",
+ "group": "Hybrid",
+ "flagged": false
+ },
+ {
+ "number": "1.4.4",
+ "name": "Resize Text",
+ "level": "AA",
+ "conformance": "Supports",
+ "responsibility": "Shared",
+ "group": "Automated",
+ "flagged": false
+ },
+ {
+ "number": "1.4.5",
+ "name": "Images of Text",
+ "level": "AA",
+ "conformance": "Supports",
+ "responsibility": "Author",
+ "group": "Manual",
+ "flagged": false
+ },
+ {
+ "number": "1.4.10",
+ "name": "Reflow",
+ "level": "AA",
+ "conformance": "Supports",
+ "responsibility": "Shared",
+ "group": "Automated",
+ "flagged": false
+ },
+ {
+ "number": "1.4.12",
+ "name": "Text Spacing",
+ "level": "AA",
+ "conformance": "Supports",
+ "responsibility": "Shared",
+ "group": "Automated",
+ "flagged": false
+ },
+ {
+ "number": "2.4.6",
+ "name": "Headings and Labels",
+ "level": "AA",
+ "conformance": "Supports",
+ "responsibility": "Shared",
+ "group": "Hybrid",
+ "flagged": false
+ },
+ {
+ "number": "2.5.3",
+ "name": "Label in Name",
+ "level": "A",
+ "conformance": "Supports",
+ "responsibility": "Shared",
+ "group": "Automated",
+ "flagged": false
+ },
+ {
+ "number": "3.3.2",
+ "name": "Labels or Instructions",
+ "level": "A",
+ "conformance": "Supports",
+ "responsibility": "Shared",
+ "group": "Hybrid",
+ "flagged": true
+ },
+ {
+ "number": "4.1.2",
+ "name": "Name, Role, Value",
+ "level": "A",
+ "conformance": "Supports",
+ "responsibility": "Shared",
+ "group": "Hybrid",
+ "flagged": false
+ }
+ ],
+ "summary": {
+ "rated": 13,
+ "levelA": 7,
+ "levelAA": 6,
+ "supports": 11,
+ "partiallySupports": 2,
+ "doesNotSupport": 0,
+ "verified": 10,
+ "automated": 4
+ }
+ },
{
"component": "LinearProgress",
"counts": {
diff --git a/packages/mui-material/src/FormLabel/FormLabel.test.js b/packages/mui-material/src/FormLabel/FormLabel.test.js
index d0233b0925a640..0a556dd71fee6c 100644
--- a/packages/mui-material/src/FormLabel/FormLabel.test.js
+++ b/packages/mui-material/src/FormLabel/FormLabel.test.js
@@ -4,9 +4,14 @@ import PropTypes from 'prop-types';
import { act, createRenderer, screen } from '@mui/internal-test-utils';
import FormLabel, { formLabelClasses as classes } from '@mui/material/FormLabel';
import FormControl, { useFormControl } from '@mui/material/FormControl';
-import { hexToRgb } from '@mui/material/styles';
+import Checkbox from '@mui/material/Checkbox';
+import Input from '@mui/material/Input';
+import { createTheme, hexToRgb } from '@mui/material/styles';
import defaultTheme from '../styles/defaultTheme';
import describeConformance from '../../test/describeConformance';
+import getOverlayAlpha from '../styles/getOverlayAlpha';
+import { blend, contrastRatio, WCAG_MINIMUM_RATIO } from '../../test/contrast';
+import { FAILING_PALETTE_COLORS, PALETTE_CONTRAST_COLORS } from '../../test/contrastContract';
describe('', () => {
const { render } = createRenderer();
@@ -188,4 +193,119 @@ describe('', () => {
});
});
});
+
+ describe('WCAG 2.2 conformance', () => {
+ describe('1.3.1 Info and Relationships', () => {
+ it('renders a legend element that names the fieldset group', () => {
+ render(
+
+ Notification method
+
+ ,
+ );
+
+ const group = screen.getByRole('group');
+ const legend = screen.getByText('Notification method');
+ expect(legend).to.have.tagName('legend');
+ expect(legend.parentElement).to.equal(group);
+ expect(group).toHaveAccessibleName('Notification method');
+ });
+
+ it('forwards htmlFor as the for attribute of the label', () => {
+ render(
+
+ Full name
+
+ ,
+ );
+
+ const label = screen.getByText('Full name');
+ expect(label).to.have.tagName('label');
+ expect(label).to.have.attribute('for', 'full-name');
+ expect(screen.getByRole('textbox')).toHaveAccessibleName('Full name');
+ });
+
+ it('does not pass the required state to a Checkbox (documented gap)', () => {
+ render(
+
+ Terms
+
+ ,
+ );
+
+ // When this fails, the gap is fixed: update FormLabel/accessibility.md and knownGaps.json.
+ expect(screen.getByRole('checkbox')).not.to.have.attribute('required');
+ });
+ });
+
+ describe('1.4.3 Contrast (Minimum)', () => {
+ it('focused labels fall short of 4.5:1 only in the documented palette colors', () => {
+ const theme = createTheme();
+ render(
+
+ {PALETTE_CONTRAST_COLORS.map((color) => (
+
+ {color}
+
+ ))}
+ ,
+ );
+
+ // A focused label is `main` on the page background.
+ const failing = PALETTE_CONTRAST_COLORS.filter((color) => {
+ const { color: textColor } = window.getComputedStyle(screen.getByText(color));
+ return (
+ contrastRatio(textColor, theme.palette.background.default) <
+ WCAG_MINIMUM_RATIO.normalText
+ );
+ });
+ expect(failing).to.deep.equal([...FAILING_PALETTE_COLORS]);
+ });
+
+ it('the dark-mode error label falls short of 4.5:1 on a Paper with elevation 2 or more', () => {
+ const theme = createTheme({ palette: { mode: 'dark' } });
+ const ratios = [2, 24].map((elevation) =>
+ contrastRatio(
+ theme.palette.error.main,
+ blend('#fff', getOverlayAlpha(elevation), theme.palette.background.paper),
+ ),
+ );
+
+ // When this fails, the gap is fixed: update FormLabel/accessibility.md and knownGaps.json.
+ ratios.forEach((ratio) => {
+ expect(ratio).to.be.lessThan(WCAG_MINIMUM_RATIO.normalText);
+ });
+ });
+ });
+
+ it('2.5.3 Label in Name: the accessible name of the field is the visible label', () => {
+ const { container } = render(
+
+ Email address
+
+ ,
+ );
+
+ // The hidden asterisk adds nothing to the name.
+ expect(container.querySelector(`.${classes.asterisk}`)).to.have.attribute(
+ 'aria-hidden',
+ 'true',
+ );
+ expect(screen.getByRole('textbox')).toHaveAccessibleName('Email address');
+ });
+
+ describe('3.3.2 Labels or Instructions', () => {
+ it('shows the asterisk, and an Input inside the FormControl gets the required state', () => {
+ const { container } = render(
+
+ Full name
+
+ ,
+ );
+
+ expect(container.querySelector(`.${classes.asterisk}`)).not.to.equal(null);
+ expect(screen.getByRole('textbox')).to.have.attribute('required');
+ });
+ });
+ });
});
diff --git a/packages/mui-material/src/FormLabel/accessibility.json b/packages/mui-material/src/FormLabel/accessibility.json
new file mode 100644
index 00000000000000..b19137be7f8de4
--- /dev/null
+++ b/packages/mui-material/src/FormLabel/accessibility.json
@@ -0,0 +1,22 @@
+{
+ "axe": "docs/data/material/components/form-label/form-label.a11y.json",
+ "criteria": {
+ "1.3.1": { "conformance": "Partially Supports", "flagged": true },
+ "1.4.3": { "responsibility": "Component" },
+ "3.3.2": { "flagged": true }
+ },
+ "notApplicable": [
+ "1.1.1",
+ "1.4.11",
+ "2.1.1",
+ "2.1.2",
+ "2.4.3",
+ "2.4.7",
+ "2.4.11",
+ "2.5.2",
+ "2.5.8",
+ "3.2.1",
+ "3.2.2",
+ "3.2.4"
+ ]
+}
diff --git a/packages/mui-material/src/FormLabel/accessibility.md b/packages/mui-material/src/FormLabel/accessibility.md
new file mode 100644
index 00000000000000..1d4ffee0e30b99
--- /dev/null
+++ b/packages/mui-material/src/FormLabel/accessibility.md
@@ -0,0 +1,323 @@
+
+
+# FormLabel accessibility conformance
+
+Rated against WCAG 2.2 Level A and AA. See the [reports legend](../accessibility.md).
+
+
+
+FormLabel labels a field or, as a `legend`, names a group. It is not focusable. A click on a label with `htmlFor` focuses or activates its field, so the field report rates the keyboard, focus, and pointer criteria.
+
+
+
+| Result | Count |
+| :-------------------- | :---- |
+| ✅ Supports | 11 |
+| ⚠️ Partially Supports | 2 |
+| ❌ Does Not Support | 0 |
+| ➖ Not Applicable | 42 |
+| 🚩 Flagged | 3/13 |
+
+## Known gaps
+
+- ⚠️ **1.3.1 Info and Relationships.** On a `required` group legend, the asterisk is `aria-hidden`, and Checkbox, Radio, and Switch do not take `required` from FormControl. Assistive technology then gets no required state.
+- ⚠️ **1.4.3 Contrast (Minimum).** A focused label takes the `main` color of its field. In light mode, `info` (`3.86:1`) and `warning` (`3.11:1`) are less than `4.5:1`. In dark mode, the error label falls below `4.5:1` on a Paper with elevation 2 or more, such as a Menu or Dialog, because the elevation overlay lightens the surface.
+
+## Success criteria
+
+### 🔍 Manual
+
+#### 1.3.2 Meaningful Sequence · A
+
+`✅ Supports` · `○ Author`
+
+
+
+- The label renders its text, then the asterisk when `required`. The asterisk is `aria-hidden`.
+
+**Manual testing steps**
+
+1. Read a form with a screen reader in browse mode.
+2. Compare the reading order of each label and its field with the visual order.
+
+
+
+**Pass:** each label comes before its field in the reading order.
+
+#### 1.3.3 Sensory Characteristics · A
+
+`✅ Supports` · `○ Author`
+
+
+
+- The label is text. Instructions in the page must not refer to a field only by its position or color.
+
+**Manual testing steps**
+
+1. Find product copy that refers to a form field.
+2. Make sure that it names the field by its label.
+
+
+
+**Pass:** each instruction names the field by its label.
+
+#### 1.4.5 Images of Text · AA
+
+`✅ Supports` · `○ Author`
+
+
+
+- The label is real text.
+
+**Manual testing steps**
+
+1. Select the text of a label with the mouse.
+
+
+
+**Pass:** the mouse selects the label text character by character.
+
+### 🔁 Hybrid
+
+#### 1.3.1 Info and Relationships · A
+
+`🚩` · `⚠️ Partially Supports` · `◐ Shared`
+
+Tested by: unit `FormLabel.test.js`
+
+
+
+- The root is a `