fix(title): title is level one heading if one is not present
Issue number: resolves #23746
What is the current behavior?
Pages do not have a level 1 heading. This level 1 heading defines the page itself (i.e. "Settings"). Without it, users relying on screen readers lack important information regarding the purpose of the page.
What is the new behavior?
ion-titlewill renderrole="heading"andaria-level="1"(i.e.h1) if all of the following are true:- There is not another level 1 heading within the parent scope of the title. The parent scope of the title is either the page (i.e.
.ion-page) or the body. - The title is used within an
ion-headerwith a landmark. Headers typically haverole="banner"except for when they are used inside of anion-menu. - The title is the first title within the parent scope.
- The title does not already have a role.
- There is not another level 1 heading within the parent scope of the title. The parent scope of the title is either the page (i.e.
Developers can override this behavior by using h1 directly or by using role="heading" or aria-level="1" on something else.
Does this introduce a breaking change?
- [ ] Yes
- [x] No
There shouldn't be a breaking change, but it's possible that someone is using a level 1 heading in a way that we aren't anticipating, which could cause duplicate level 1 headings to be set. For example, an application could set an h1 element after a delay.
As a result, I am merging this into feature-8.0 so we can get some field testing in the Ionic 8 beta before shipping.
Other information
According to https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#avoid_using_multiple_h1_elements_on_one_page there should generally be only a single h1 element on a page. h1 elements should never be nested (which we account for in this PR). However, for single page apps, each view is essentially its own page and needs an h1. h1 elements in inactive views are always hidden using display: none, so users should never be able to access them anyways. I've added Axe test to verify that Axe does not warn for this use case.
Dev build: 7.5.8-dev.11702664817.19cab605