Skip to content

Commit 23763ab

Browse files
authored
fix(header): use aria attributes to hide small title when collapsed (#30027)
Issue number: resolves #29347 --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> Focusable elements like buttons cannot be accessed within the `ion-header` when it's collapsed. They're only accessible once the small title is displayed. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - Moved the `aria-hidden` from the header to `ion-title`, this aligns with native. - Updated existing test. ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change: 1. Describe the impact and migration path for existing applications below. 2. Update the BREAKING.md file with the breaking change. 3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer for more information. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> Dev build: `8.4.1-dev.11732064156.12837790`
1 parent 470decc commit 23763ab

File tree

2 files changed

+33
-6
lines changed

2 files changed

+33
-6
lines changed

core/src/components/header/header.utils.ts

+23-2
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,34 @@ export const handleToolbarIntersection = (
167167

168168
export const setHeaderActive = (headerIndex: HeaderIndex, active = true) => {
169169
const headerEl = headerIndex.el;
170+
const toolbars = headerIndex.toolbars;
171+
const ionTitles = toolbars.map((toolbar) => toolbar.ionTitleEl);
170172

171173
if (active) {
172174
headerEl.classList.remove('header-collapse-condense-inactive');
173-
headerEl.removeAttribute('aria-hidden');
175+
176+
ionTitles.forEach((ionTitle) => {
177+
if (ionTitle) {
178+
ionTitle.removeAttribute('aria-hidden');
179+
}
180+
});
174181
} else {
175182
headerEl.classList.add('header-collapse-condense-inactive');
176-
headerEl.setAttribute('aria-hidden', 'true');
183+
184+
/**
185+
* The small title should only be accessed by screen readers
186+
* when the large title collapses into the small title due
187+
* to scrolling.
188+
*
189+
* Originally, the header was given `aria-hidden="true"`
190+
* but this caused issues with screen readers not being
191+
* able to access any focusable elements within the header.
192+
*/
193+
ionTitles.forEach((ionTitle) => {
194+
if (ionTitle) {
195+
ionTitle.setAttribute('aria-hidden', 'true');
196+
}
197+
});
177198
}
178199
};
179200

core/src/components/header/test/condense/header.e2e.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@ import { configs, test } from '@utils/test/playwright';
33

44
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
55
test.describe(title('header: condense'), () => {
6-
test('should be hidden from screen readers when collapsed', async ({ page }) => {
6+
test('should hide small title from screen readers when collapsed', async ({ page }) => {
7+
test.info().annotations.push({
8+
type: 'issue',
9+
description: 'https://github.com/ionic-team/ionic-framework/issues/29347',
10+
});
11+
712
await page.goto('/src/components/header/test/condense', config);
813
const largeTitleHeader = page.locator('#largeTitleHeader');
914
const smallTitleHeader = page.locator('#smallTitleHeader');
15+
const smallTitle = smallTitleHeader.locator('ion-title');
1016
const content = page.locator('ion-content');
1117

12-
await expect(smallTitleHeader).toHaveAttribute('aria-hidden', 'true');
18+
await expect(smallTitle).toHaveAttribute('aria-hidden', 'true');
1319

1420
await expect(largeTitleHeader).toHaveScreenshot(screenshot(`header-condense-large-title-initial-diff`));
1521

@@ -24,15 +30,15 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, c
2430
* Playwright can't do .not.toHaveAttribute() because a value is expected,
2531
* and toHaveAttribute can't accept a value of type null.
2632
*/
27-
const ariaHidden = await smallTitleHeader.getAttribute('aria-hidden');
33+
const ariaHidden = await smallTitle.getAttribute('aria-hidden');
2834
expect(ariaHidden).toBeNull();
2935

3036
await content.evaluate(async (el: HTMLIonContentElement) => {
3137
await el.scrollToTop();
3238
});
3339
await page.locator('#smallTitleHeader.header-collapse-condense-inactive').waitFor();
3440

35-
await expect(smallTitleHeader).toHaveAttribute('aria-hidden', 'true');
41+
await expect(smallTitle).toHaveAttribute('aria-hidden', 'true');
3642
});
3743
});
3844
});

0 commit comments

Comments
 (0)