Skip to content

Commit fd6d959

Browse files
committed
Dev: warn when slider controls missing an accessible name (help with #33669)
1 parent 546bac7 commit fd6d959

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

packages/react-dom-bindings/src/client/ReactDOMComponent.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,39 @@ function validatePropertiesInDevelopment(type: string, props: any) {
111111
'probably not intentional.',
112112
);
113113
}
114+
115+
// Dev-time accessibility hint: certain controls (for example sliders)
116+
// must have an accessible name for screen readers to announce them
117+
// correctly on some platforms (notably Windows). We can't reliably
118+
// detect associated <label> elements here, so warn when common name
119+
// sources are missing to help authors catch the issue early.
120+
try {
121+
const hasAccessibleNameProp =
122+
props['aria-label'] != null || props['aria-labelledby'] != null ||
123+
props.title != null;
124+
125+
// Check for implicit input type=range -> role=slider
126+
if (type === 'input') {
127+
const inputType = props.type;
128+
if (inputType === 'range' && !hasAccessibleNameProp) {
129+
console.error(
130+
'A control with role `slider` (\"<input type=\"range\">\") ' +
131+
'is missing an accessible name. Add `aria-label`, `aria-labelledby` ' +
132+
'or a `title` so screen readers can announce the control.',
133+
);
134+
}
135+
}
136+
137+
// Check for explicit role=slider on any element
138+
if (props.role === 'slider' && !hasAccessibleNameProp) {
139+
console.error(
140+
'An element with `role="slider"` is missing an accessible name. ' +
141+
'Add `aria-label`, `aria-labelledby` or `title` so screen readers can announce the control.',
142+
);
143+
}
144+
} catch (e) {
145+
// Defensive: in case props accessors throw.
146+
}
114147
}
115148
}
116149

packages/react-dom/src/__tests__/ReactDOMInvalidARIAHook-test.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,27 @@ describe('ReactDOMInvalidARIAHook', () => {
8686
]);
8787
});
8888
});
89+
90+
describe('slider accessible name warning', () => {
91+
it('should warn when <input type="range"> is missing an accessible name', async () => {
92+
jest.resetModules();
93+
const React = require('react');
94+
const ReactDOMClient = require('react-dom/client');
95+
const act = require('internal-test-utils').act;
96+
const assertConsoleErrorDev =
97+
require('internal-test-utils').assertConsoleErrorDev;
98+
99+
const container = document.createElement('div');
100+
const root = ReactDOMClient.createRoot(container);
101+
102+
await act(() => {
103+
root.render(<input type="range" />);
104+
});
105+
106+
assertConsoleErrorDev([
107+
'A control with role `slider` ("<input type="range">") is missing an accessible name. Add `aria-label`, `aria-labelledby` or a `title` so screen readers can announce the control.\n' +
108+
' in input (at **)',
109+
]);
110+
});
111+
});
89112
});

0 commit comments

Comments
 (0)