Skip to content

Commit 48ff8bd

Browse files
authored
Omit redundant role="heading" on native heading elements (#2898)
1 parent 7744567 commit 48ff8bd

3 files changed

Lines changed: 43 additions & 2 deletions

File tree

‎packages/react-native-web/src/exports/createElement/__tests__/index-test.js‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,23 @@ describe('exports/createElement', () => {
477477
expect(getAttribute(roleIsNone, 'role')).toBe('presentation');
478478
});
479479

480+
test('accessibilityRole "header" renders a native heading without role="heading"', () => {
481+
const { container: heading } = render(
482+
createElement('div', { accessibilityRole: 'header' })
483+
);
484+
expect(heading.firstChild.nodeName).toBe('H1');
485+
expect(getAttribute(heading, 'role')).toBeNull();
486+
487+
const { container: levelTwo } = render(
488+
createElement('div', {
489+
accessibilityRole: 'header',
490+
'aria-level': 2
491+
})
492+
);
493+
expect(levelTwo.firstChild.nodeName).toBe('H2');
494+
expect(getAttribute(levelTwo, 'role')).toBeNull();
495+
});
496+
480497
test('accessibilityRoleDescription', () => {
481498
const { container: isEmpty } = render(
482499
createElement('div', { accessibilityRoleDescription: null })

‎packages/react-native-web/src/modules/createDOMProps/__tests__/index-test.js‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,17 @@ describe('modules/createDOMProps', () => {
241241
expect(props.role).toEqual('button');
242242
});
243243

244+
test('omits redundant role="heading" on native heading elements', () => {
245+
expect(
246+
createDOMProps('h1', { accessibilityRole: 'header' }).role
247+
).toBeUndefined();
248+
expect(
249+
createDOMProps('h3', { role: 'heading', 'aria-level': 3 }).role
250+
).toBeUndefined();
251+
// Non-heading hosts still receive the ARIA role.
252+
expect(createDOMProps('div', { role: 'heading' }).role).toEqual('heading');
253+
});
254+
244255
test('prop "nativeID" becomes "id"', () => {
245256
const nativeID = 'Example.nativeID';
246257
const props = createProps({ nativeID });

‎packages/react-native-web/src/modules/createDOMProps/index.js‎

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,8 +377,21 @@ const createDOMProps = (elementType, props, options) => {
377377
}
378378

379379
if (role != null) {
380-
// 'presentation' synonym has wider browser support
381-
domProps['role'] = role === 'none' ? 'presentation' : role;
380+
// h1-h6 already have the heading role. An explicit role="heading" on
381+
// them fails heading audits such as axe "page-has-heading-one".
382+
const isNativeHeading =
383+
role === 'heading' &&
384+
(elementType === 'h1' ||
385+
elementType === 'h2' ||
386+
elementType === 'h3' ||
387+
elementType === 'h4' ||
388+
elementType === 'h5' ||
389+
elementType === 'h6');
390+
391+
if (!isNativeHeading) {
392+
// 'presentation' synonym has wider browser support
393+
domProps['role'] = role === 'none' ? 'presentation' : role;
394+
}
382395
}
383396

384397
const _ariaRoleDescription =

0 commit comments

Comments
 (0)