Site Navigation
UI pattern
menu roles, holds accessible links, and lets keyboard users reach every link.Site navigation usually sits in the page header, though a sidebar or a footer can hold it too.
Site navigation can be a simple list of links, or a structure that groups related links in disclosures, or a mix of both. When it has disclosures, each disclosure control stands for a section of the site, and opening it reveals the links to pages in that section.
Most people call a site's navigation a "menu", but it isn't an application menu. The ARIA menu and menubar roles identify widgets that offer commands that act on the page, and site navigation only takes users to other pages, so those roles don't fit it.
When to Use
Use site navigation when:
- You have a set of links that take users between the main pages or sections of a site.
- The navigation landmark should be available throughout the site.
Don't use site navigation when:
- The controls run commands or change settings on the current page. Use buttons, a menu button, or a menu instead.
- The links show where the current page sits in a hierarchy. Use a breadcrumb.
- The links point to sections of the current page, such as a table of contents. A navigation landmark can still hold them, but they don't need the panels and site-wide structure this entry describes.
Examples
Code in this section is meant to demonstrate techniques rather than requirements and lacks features needed in a production application.
All three examples put a list of links in a <nav> element named "Main" and mark the link to the page users are on with aria-current="page".
Site Navigation With Links
The simplest site navigation component is a <nav> element holding a list of links. The <nav> element supplies the navigation landmark, and the list tells assistive technology users how many links there are.
Site navigation HTML
<nav aria-label="Main">
<ul>
<li>
<a href="/" aria-current="page">Home</a>
</li>
<li>
<a href="/about/">About</a>
</li>
<li>
<a href="/products/">Products</a>
</li>
</ul>
</nav>Site Navigation With Disclosure Panels
This build has a top-level list. Each list item holds a link to its section's main page, followed by a disclosure that reveals a list of links to the pages within that section, so the markup reflects the site's hierarchy.
The two constructions that follow use the disclosure pattern. The first uses <button> elements to show and hide the panels, and the second is a native HTML build from <details> and <summary> elements. Refer to Disclosure for more detail and example JavaScript.
In either construction, each disclosure control can open its panel of links in a "dropdown" that overlays the page content. These examples don't show the CSS needed to do that. The dropdowns aren't popups that need aria-haspopup because they don't claim an ARIA role and focus doesn't move into them automatically.
Each link in an open panel is a tab stop. A build may let keyboard users move focus between the links in an open panel with the arrow keys, but that isn't a requirement.
Site navigation HTML with disclosure buttons
<nav aria-label="Main">
<ul>
<li>
<a href="/" aria-current="page">Home</a>
</li>
<li>
<a href="/about/">About</a>
<button
type="button"
aria-expanded="false"
aria-controls="about-panel"
aria-label="More About pages">
</button>
<ul id="about-panel" hidden>
<li>
<a href="/about/history/">History</a>
</li>
<li>
<a href="/about/team/">Team</a>
</li>
</ul>
</li>
<li>
<a href="/products/">Products</a>
<button
type="button"
aria-expanded="false"
aria-controls="products-panel"
aria-label="More Products pages">
</button>
<ul id="products-panel" hidden>
<li>
<a href="/products/hardware/">Hardware</a>
</li>
<li>
<a href="/products/software/">Software</a>
</li>
</ul>
</li>
</ul>
</nav>The <details> and <summary> disclosure construction supplies the expand/collapse mechanism natively and doesn't need the aria-expanded or aria-controls attributes.
Site navigation HTML with details and summary
<nav aria-label="Main">
<ul>
<li>
<a href="/" aria-current="page">Home</a>
</li>
<li>
<a href="/about/">About</a>
<details>
<summary aria-label="More About pages">
<span aria-hidden="true">â–¾</span>
</summary>
<ul>
<li>
<a href="/about/history/">History</a>
</li>
<li>
<a href="/about/team/">Team</a>
</li>
</ul>
</details>
</li>
<li>
<a href="/products/">Products</a>
<details>
<summary aria-label="More Products pages">
<span aria-hidden="true">â–¾</span>
</summary>
<ul>
<li>
<a href="/products/hardware/">Hardware</a>
</li>
<li>
<a href="/products/software/">Software</a>
</li>
</ul>
</details>
</li>
</ul>
</nav>Structure and Semantics
A site navigation component is a navigation landmark that holds a list of links, sometimes with disclosure controls that reveal nested lists of more links. The <nav> element supplies the landmark with no ARIA. When the markup can't use <nav>, a generic element with role="navigation" does the same job.
Lists carry the structure. The top-level list holds one item per link or section, and each panel's list sits inside the item that holds its disclosure control. Screen reader users then hear how many items each level has and which section a link belongs to.
The link to the page users are on carries aria-current="page", so assistive technology reports it as the current page. Give each link a name that tells its destination apart from the others, and use the same name only for links to the same page.
Keep the navigation landmark's content to links and the disclosure controls that reveal them. Other controls, such as a search field or a sign-in button, belong outside the navigation landmark, where users don't mistake them for destinations.
Navigation Landmark
A site navigation component is a navigation landmark. Screen reader users can jump straight to it from anywhere on the page or skip past it to the content, and it marks where the site's links start and end.
Sits inside a navigation landmark
Reported as: Missing navigation semantics
A site navigation component must be enclosed in a navigation landmark.
When the links sit in a plain <div> or a bare <ul>, nothing identifies them as navigation. Users who move through the page by landmark never find them and have to read from the top of every page to reach them. Nothing separates the links that move users around the site from the links in the content.
Wrap the set in a <nav> element, or give its container role="navigation" when the element can't be changed.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Keeps navigation landmarks apart
Reported as: Nested navigation elements
A site navigation landmark shouldn't contain another navigation landmark, or sit inside one.
When a breadcrumb or a section menu with its own <nav> is rendered inside the site navigation landmark, assistive technology reports the inner landmark as part of the outer one. Users moving by landmark meet the same region twice and can't tell whether they've reached somewhere new.
Keep each navigation landmark separate. Remove the inner landmark, or move the set it wraps out of the site navigation landmark, so each landmark stands for one set of links.
Severity: Moderate
Names the navigation landmark
Reported as: Navigation name
When a page has more than one navigation landmark, the site navigation landmark should have a name that tells it apart from the others.
When several landmarks are all reported only as "navigation", screen reader users choosing from a list of landmarks have nothing to choose by. They have to enter each one to find the site navigation landmark.
Name it with aria-labelledby pointing at a visible heading, or with aria-label, using a name like "Main". Leave the word "navigation" out of the name, or screen reader users hear it twice. When the same links appear in a second landmark, such as the footer, give both the same name.
Severity: Minor
Site Navigation Has Links
Site navigation holds links to the pages of the site. Users come to the landmark for its links, so without them it offers nothing to follow.
Gives links the required role
Reported as: No group members with required role
A site navigation component must contain elements with the link role.
When the component's items are built from elements with click handlers but no link role, screen reader users enter the landmark and hear text with no way to tell it leads anywhere. They also can't list the site's links, and voice control users can't target them by name.
Make each destination an <a> element with an href, or give a custom element role="link".
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Role
Each part of a site navigation component carries its own role:
- The outer container carries the
navigationrole. - Each list carries the
listrole, and each of its items carrieslistitem. - Each link carries the
linkrole. - Each disclosure control is a
<summary>element or carries thebuttonrole.
Has the correct role
Reported as: Element has incorrect role
Each part of the site navigation component must expose the role listed above.
When a part doesn't expose its role, assistive technology misreports it. Screen reader users hear a link built from a <span> as plain text, and a disclosure control built from a <div> gives no sign that it can be operated, so users can't tell which items to follow and which to open.
Build the component from native elements: <nav>, <ul> and <li>, <a> with an href, and a <button> or a <summary> for each disclosure control. Add the matching role only when an element can't be native.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Applies role to the correct element
Reported as: Incorrect root element
Sanity check. Evinced checks that the navigation role sits on the element that holds the whole site navigation component, rather than on an element inside it. This check runs on every UI pattern, not only on site navigation components.
The navigation role should sit on the outer element of the site navigation component, the one that holds every link and disclosure control.
When the role sits on an inner part, such as one of the nested lists or a wrapper around some of the links, the landmark covers only that part. Users who jump to the landmark land partway through the component and don't reach the links outside it.
Put the navigation role, or the <nav> element, on the element that contains the whole set, and remove it from the inner parts. If the test selected an inner element by mistake, select the component's <nav> element itself and run the test again.
Button Name
A disclosure control in a site navigation component needs an accessible name that says which section of the site its panel holds. When a link to the section's main page sits beside the control, give the control a name that tells it apart from the link, such as "More About pages".
Has an accessible name
Reported as: Accessible name
A disclosure control in a site navigation component must have an accessible name that says which section it reveals.
When the control holds only an icon, such as a chevron, or an image with empty alt text, users get a control they can operate and can't identify. Every disclosure control in the component then exposes the same name or none, so finding a section means opening each panel in turn.
Name the control from the text inside it. When the design shows only an icon, give a child image meaningful alt text, or give a button an aria-label or an aria-labelledby pointing at visible text.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Summary has an accessible name
Reported as: Summary has no accessible name
When a section of a site navigation component is built from a <details> element, its <summary> must have an accessible name that says which section it reveals.
When the <summary> is empty, or holds only an icon or an image with empty alt text and has no aria-label, users get a control they can't identify. Every disclosure control in the component then exposes the same name or none.
Put the section's name inside the <summary>. When the design leaves no visible text to use, give a child image meaningful alt text, or give the <summary> an aria-label.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Builds the control from a summary
Reported as: Native disclosure is missing summary element
A section of a site navigation component built from a <details> element must have a <summary> element with an accessible name as its first child.
When the first child is the panel's list of links, the browser still renders a control and names it with a default string, usually "Details". Users get a set of identically named controls in the component and no way to tell which section holds the page they want.
Put a <summary> first inside the <details> element and give it the section's name.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Link Name
A site navigation link's name is the name of the page it leads to, ideally the same title that page shows in its main heading, so users recognize the page when they arrive.
Has an accessible name
Reported as: Accessible name
A site navigation link must have an accessible name that identifies the page it leads to.
Without an accessible name, assistive technology can only report that a link is there, so screen reader users can't tell where it goes, and voice control users have no name to speak to follow it. When the link is a home link drawn as a logo, users lose the usual way back to the start of the site.
Give each link visible text naming its page. When a link shows only an icon or a logo, give the image meaningful alt text or give the link an aria-label.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Accessibility Label
A site navigation panel is usually a list of links and needs no other role. When a panel carries a role such as group or region, it needs an accessible name, and the disclosure control that reveals it supplies one.
Names the panel from its control
Reported as: Disclosure panel has no accessible name
A site navigation panel that carries a role should take its accessible name from the disclosure control that reveals it.
When a panel has a group or region role and no name, assistive technology reports an unnamed group or region. Screen reader users who move into the panel's links can't tell which section of the site they're in.
Give the control an id and point the panel's aria-labelledby at it, so the name can't drift from the control's wording. Give the panel a role only when it needs one.
Severity: Minor
aria-expanded
A disclosure control built as a button uses aria-expanded to report whether its panel is open, from the moment the page loads. Whether the value changes when users operate the button belongs to Toggle Activation. A disclosure control built from a <summary> reports its state through the open attribute on its <details> element and takes no aria-expanded.
Reflects aria-expanded state
Reported as: Conflicting aria-expanded value
The aria-expanded value of a button that opens a site navigation panel must match whether the panel is showing: false while its links are hidden and true while they're available.
When the value is derived from something other than the panel's real state, it reports the opposite of what's on screen. Screen reader users skip a panel of links that's open in front of them, or go looking for links that were never revealed.
Set the attribute from the same state that decides whether the panel renders.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Updates aria-expanded
Reported as: Aria-expanded value did not change
The aria-expanded value of a button that opens a site navigation panel must change whenever the panel opens or closes, including when the panel closes because users pressed Escape or moved focus out of the landmark.
When the panel changes and the value doesn't, the attribute goes on reporting the state the panel was in before, so screen reader users are told a section's links are hidden while they're showing, or the reverse.
Change the attribute in the same step that shows or hides the panel, whatever caused it to open or close.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Has aria-expanded
Reported as: Missing aria-expanded attribute
A button that opens a site navigation panel must carry aria-expanded, in the collapsed state as well as the expanded one.
When the attribute is absent, nothing in the markup says the button reveals anything, so screen reader users have no reason to expect a panel of links to appear and can't tell afterward whether activating it worked.
Set it to false from the start rather than adding it once the panel has been opened.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Disabled
The links and disclosure controls are the only parts of a site navigation component that can be disabled. The landmark, its lists, and their items have no disabled state, so to make a whole section unavailable, disable or remove the controls in it.
The recommended method to disable a link is to remove the href attribute from its <a> element, which removes its link role and its tab stop. A link that has to keep its role while it's disabled sets role="link" and aria-disabled="true" instead.
A <summary> has no disabled state, so a disclosure control that has to be disabled is built as a button. It takes the disabled attribute when it's a native <button>, and aria-disabled="true" when it's built from a generic element.
Disables only when role allows
Reported as: Component does not support disabled state
A disabled state must be declared only on a link or a button in a site navigation component.
When aria-disabled is set on the <nav> element, a list, or a list item, the role has no disabled state to report. ARIA 1.2 deprecated aria-disabled on the navigation role. Assistive technology may ignore the attribute or misreport it, and the links inside stay fully operable, so users can't tell what the design meant to turn off.
Remove the attribute from the container. Disable the individual links or buttons that are unavailable, or leave them out of the component.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Disables only elements that support it
Reported as: Element type does not support disabled state
An element in a site navigation component must carry disabled or aria-disabled only when its role supports a disabled state.
When the state sits on an element whose role has none, such as a wrapper, a list item or a heading, assistive technology may drop it or report it on something users can't operate, while the control that really is unavailable is still reported as available.
Remove the attribute from that element, and set the disabled state on the control itself, using an element or role that supports it, such as a native <button>.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Avoids conflicting disabled states
Reported as: Conflicting disabled values
A site navigation link or button must declare its disabled state one way only.
When a native <button> carries disabled alongside aria-disabled="false", or a link carries disabled alongside aria-disabled, the two can disagree, and assistive technology can report a different state from the one the browser enforces. Users can't tell whether the section or the page is available.
Use the disabled attribute on a native <button> and aria-disabled on a button built from a generic element, never both. Disable a link by removing its href, or with role="link" and aria-disabled="true" alone when it has to keep its role.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Uses aria-disabled rather than disabled
Reported as: Element does not support the disabled attribute
A site navigation link, or a button built from a generic element, must convey its disabled state with aria-disabled rather than disabled.
Browsers ignore the disabled attribute on <a>, <div>, and <span> elements. When a link or button carries it, assistive technology still reports it as available and it still works, however grayed out it looks. Users then try to follow a link or open a panel the design means to be unavailable.
Remove href from a link's <a> element to disable it, adding role="link" and aria-disabled="true" when it has to keep its role. On a generic button, set aria-disabled="true" and block activation in its handlers, or switch to a native <button> and use disabled.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Unexpected Interactives
Site navigation holds links and the disclosure buttons that reveal groups of them. A control of another kind among them, such as an element with a menu item role or a form field, doesn't fit how users move through the navigation and use it.
Holds only expected controls
Reported as: Unexpected interactives in menu
A site navigation component must hold only links and disclosure buttons.
When another kind of control sits among them, assistive technology presents it in a way the rest of the navigation doesn't match, and keyboard users may not reach or operate it the way they expect.
Keep the navigation to links and disclosure buttons. Move a search field or another control out of the navigation landmark, and give it a landmark of its own when it needs one.
Severity: Minor
Forbidden Roles
Site navigation doesn't use the menu, menubar, or menuitem roles. Those roles promise the keyboard behavior of an application menu, which users expect to be driven by the arrow keys from a single tab stop, and a set of links doesn't need it. Links and disclosure controls in a navigation landmark are simpler to build and work the way users expect.
Reserves menu roles for menus
Reported as: Menu as a nav element
A site navigation component should be built from links in a navigation landmark rather than with the menu or menubar role.
When the bar is a menubar and its links are menuitem elements, screen reader users are told they've reached a set of commands. They press the arrow keys and nothing happens, or the Tab key skips the whole set. The component also doesn't appear in the page's list of landmarks, where users look for it.
Use a <nav> element holding lists of links and disclosure controls. Keep the menu roles for menus of commands that act on the page.
Severity: Minor
Forbidden Interactive Children
A site navigation link or disclosure control contains only its name, and perhaps an icon. A disclosure control placed inside the link to its section's main page leaves it ambiguous whether a click or a key press follows the link or opens the panel.
Avoids nested interactives
Reported as: Forbidden interactive children; Nested interactive elements
A site navigation link or disclosure control must not contain another interactive element, such as a button or a second link.
When one control is nested inside another, browsers and assistive technologies handle it differently. A disclosure control's children are presentational, so screen reader users can't perceive or follow a link inside one. A disclosure control inside a link gives every click or key press two plausible targets, and users can't tell which one they'll reach.
Take the inner control out and place it beside the other in the list item, as a disclosure control sits beside its section's link.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Relationships
A site navigation component owns its links and disclosure controls, and holds them inside its landmark and lists in the DOM. That nesting relates them to the landmark and to each other without any attribute: assistive technology reports each link as part of the landmark and of its list.
Each disclosure control operates the panel it reveals rather than owning it. In a <details> element, the panel is the content after the <summary>. A button's panel sits right after it in the same list item, and the button's aria-controls names it.
aria-controls
A disclosure control built as a button should carry aria-controls naming its panel, as a best practice. When the panel's list sits right after the button, users reach the links by reading on, and the attribute states the relationship for the assistive technology that uses it. A <summary> needs no aria-controls, because its <details> element already holds the panel.
Controls a single target
Reported as: Aria-controls has multiple targets
The aria-controls attribute of a button that opens a site navigation panel should name one element, the panel that holds its section's links.
When it lists several ids, the button claims to drive several separate elements, and assistive technology that offers to move users to the controlled content has to pick a target or offer none.
Point aria-controls at the single element that holds the panel. When the panel is made of several elements, wrap them in one container and name that container instead.
Severity: Minor
References valid aria-controls
Reported as: Invalid aria-controls reference
The aria-controls attribute of a button that opens a site navigation panel must name an element that exists on the page.
When the id matches nothing in the document, the reference fails quietly. Assistive technology finds no target, so it can't tell users which panel the button opens, and the markup still looks correct to anyone reading it.
Generate the panel's id and the aria-controls value from one source. When the panel exists only while it's open, add the attribute when the panel appears and remove it when the panel is destroyed.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Sets aria-controls
Reported as: Missing aria-controls attribute
A button that opens a site navigation panel should identify the panel with aria-controls.
When the attribute is missing, nothing in the markup states which panel of links the button affects, and assistive technology that uses the relationship has nothing to offer users.
Add aria-controls to the button and set its value to the panel's unique id. Keep the panel right after the button in its list item rather than relying on the attribute to lead users there.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
aria-owns
Keep every link and disclosure control inside the site navigation landmark in the DOM, in the order users meet them. Support for aria-owns varies, and focus and event handling still follow the DOM. When a framework renders a panel elsewhere in the page, for example at the end of the document, the panel is better placed inside the landmark.
Avoids aria-owns
Reported as: Avoid aria-owns
General check. Evinced checks that the site navigation component doesn't use aria-owns to claim links, disclosure controls, or panels rendered elsewhere in the document. This check runs on every UI pattern, not only on site navigation components.
A site navigation component should hold its links and panels in the DOM rather than claim them with aria-owns.
When aria-owns pulls a panel of links into the component from elsewhere, those links land after the component's own items in the accessibility tree while focus still follows the DOM. Screen reader users hear a section's links away from its disclosure control, and the Tab key reaches them in a different order.
Assistive technology that doesn't honor the attribute reports the links outside the landmark, so screen reader users get only part of the site's navigation.
Put each panel inside the list item that holds its disclosure control in the DOM, and remove aria-owns. When a framework renders the panels elsewhere, render the whole component there instead.
Owns only conforming roles
Reported as: Invalid aria-owns values
General check. Evinced checks that every element a site navigation list claims with aria-owns is a list item. This check runs on several UI patterns.
When a list in a site navigation component uses aria-owns anyway, each element it references should be a list item.
When the list owns a link, a disclosure control or a panel that isn't a list item, its item count and positions stop matching the navigation, and screen reader users hear a list whose items don't add up.
Put each link and disclosure control in its own list item inside the list in the DOM, and remove aria-owns, as the section intro describes.
Operation
Users operate a site navigation component with the same keys as any set of links and buttons. The Tab key and Shift + Tab move focus through the links and disclosure controls in order, and through the links in a panel while it's open. Enter follows a focused link. Enter or Space opens or closes a focused disclosure control's panel. With a pointer, clicking or tapping does the same.
When a panel is open, pressing Escape closes it and returns focus to its disclosure control, whether focus was on the control or on a link in the panel. Moving focus out of the landmark also closes an open panel. The arrow keys, Home, and End can also move focus between the items, but they supplement the Tab key rather than replace it.
Focus Sequence
Each link and disclosure control in a site navigation component is one tab stop, and keyboard users reach them with the Tab key in the order they appear. A closed panel's links are out of the tab order: hide a button's panel with the hidden attribute or display: none rather than moving it off screen, so keyboard users don't land on links nobody can see.
Reachable by keyboard
Reported as: Keyboard accessible
A site navigation link or disclosure control must be reachable with the Tab key.
When it's built from an element that isn't natively focusable, such as a <span> with a click handler, keyboard users can't reach it, or the pages behind it.
Use an <a> element with an href for a link, and a <button> or a <summary> element for a disclosure control. When a custom element can't be avoided, add tabindex="0" to put it in the tab order, and don't set tabindex to a value greater than 0, which takes it out of the component's order.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Skips tab order when disabled
Reported as: Disabled element focusable
A site navigation link or button that presents as disabled should not be in the tab order.
When a disabled link or button keeps its tab stop, keyboard users moving through the component land on an item they can't use.
Remove href from a disabled link's <a> element, which takes it out of the tab order, and set role="link" and aria-disabled="true" when it has to keep its role. Use the disabled attribute on a native <button>. On a custom link or button, remove tabindex="0" while it's disabled.
If users need to find the item and learn why it's unavailable, it can keep its tab stop: set aria-disabled="true", make sure activating it does nothing, and reference visible text giving the reason with aria-describedby.
Severity: Minor
Element that carries role receives focus
Reported as: Focusable offset
Focus on a site navigation link or disclosure control must land on the element that carries its role, not on a descendant.
When focus lands on a child of the element with the role, users tabbing through the component aren't told what they've reached, and screen readers may not announce the aria-current state that marks the current page or a button's aria-expanded state.
Use an <a> element with an href, a <button>, or a <summary>. Otherwise, keep tabindex="0" on the element that carries the role, and remove focusability from the descendant that was taking focus.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Unreachable Link
Every link in a site navigation component can be reached and followed with the keyboard, including the links in a panel. A panel's links are reachable only when its disclosure control can be operated from the keyboard and opening it puts the links in the tab order.
Makes every link reachable
Reported as: Unreachable links
Every link in a site navigation component must be reachable and operable with the keyboard.
When a panel opens only on hover, when its disclosure control can't be focused or doesn't respond to Enter and Space, or when a link has no href, keyboard users can't reach those pages. Voice control users can't target a link that isn't exposed either.
Make each link an <a> element with an href. Make each panel's disclosure control keyboard operable and have it report its state, and hide a closed panel in a way that removes its links from the tab order and restores them when it opens.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Keyboard Activation
A disclosure control in a site navigation component activates with either Enter or Space, as any button does. A native <button> and a <summary> respond to both keys with no script, and a button built from a generic element has to be given that behavior.
Operable by keyboard
Reported as: Button not activated by keyboard
A button that opens a site navigation panel must open and close the panel when keyboard users activate it.
When a button built from a generic element handles only the click event, keyboard users can focus it but can't reveal the links in its panel, so they can't reach those pages.
Use a native <button> element, which is keyboard operable on its own. Otherwise, add keyboard event listeners that either toggle the panel or create a click event that does.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Ignores keyboard when disabled
Reported as: Disabled button keyboard activation
A button that opens a site navigation panel and reports itself as disabled should reject keyboard activation.
When a button carries aria-disabled="true" but Enter or Space still opens its panel, screen reader users are told the section is unavailable and then find it isn't, which may confuse them or undermine their trust in the component.
Use a native <button>, which blocks interaction when disabled is set. Otherwise, check the disabled state in the keyboard handlers and return before toggling anything.
Severity: Serious
Activates with Enter and Space
Reported as: Button requires space key activation
A button that opens a site navigation panel must activate with Space as well as Enter, as a <button> element does.
When only Enter works, users who press Space, as they would on any other button, may conclude the button is unresponsive and never reach the section's links.
Add a Space keyup handler that toggles the panel, or use a native <button> element.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Link Activation
A site navigation link that leads to an available page goes there when users click it or press Enter. A disabled link does nothing.
Activates with the Enter key
Reported as: Link cannot be activated with keyboard
A site navigation link must go to its page when users press Enter.
When a custom link has only a click handler, keyboard users press Enter on it, get no response, and can't reach that page from the navigation landmark.
Use an <a> element with an href attribute, which follows the link with a pointer or the Enter key with no code, or give a custom link a keydown handler for Enter that runs the same navigation code as its click handler.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Ignores activation when disabled
Reported as: Disabled element active
A site navigation link that presents as disabled must not navigate when it's activated.
When a link carries aria-disabled="true" or is styled to look unavailable but keeps its href or its click and key handlers, users can still activate it and land on a page they were told wasn't available.
Remove href from the link's <a> element to disable it, and set role="link" when it has to keep its role. For a custom link, have the event listeners check the disabled state and return before navigating.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Toggle Activation
Activating a disclosure control in a site navigation component opens or closes its panel and updates the state the control reports, on every activation and by every route: a pointer click, Enter, and Space. A control that presents as disabled does neither.
Updates the state on activation
Reported as: Element's state did not change
A button that opens a site navigation panel must update aria-expanded every time it's operated.
Nothing looks broken to sighted users, who watch the panel open and close, while screen reader users are told it's still in the state it started in. After a few presses with no change in what they hear, they decide the button is broken and miss the section's links.
Derive the attribute from the same state that decides whether the panel shows, and handle pointer and keyboard activation through one path rather than two.
Evinced reports this issue as Critical or as Serious, depending on the context where it shows up.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Returns to its earlier state
Reported as: Toggle state not resetting
When a button that opens a site navigation panel is activated twice, aria-expanded must return to the value it started with.
When the code assigns a fixed value on activation instead of inverting the current one, the attribute stops tracking the panel after the first press. The panel goes on opening and closing, and screen reader users are told a closed panel is open.
Invert the state on each activation rather than assigning a fixed value.
Evinced reports this issue as Critical or as Serious, depending on the context where it shows up.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Leaves native state to HTML
Reported as: Invalid toggle attribute
When a section of a site navigation component is built from a <details> element and carries aria-expanded on the <details> or its <summary> (not recommended), the value must stay consistent with the open attribute.
The browser derives the state from open while assistive technology reports the ARIA value, and nothing updates the attribute when the section opens. Screen reader users are told that a panel of links they've just opened is closed.
Remove aria-expanded and let the native state stand. When it can't be removed yet, update it from the toggle event on the <details> element so it tracks open.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Ignores activation when disabled
Reported as: Disabled element active
A button that opens a site navigation panel and presents as disabled must not open the panel when it's activated.
aria-disabled="true" changes only what's reported, not what the browser allows, so the click and key handlers keep firing unless the code checks the state. Users are told a section isn't available and then find that it opens.
Check the disabled state at the top of the handler and return before changing anything, covering the pointer and keyboard paths. On a native button, use the disabled attribute, which stops activation in the browser.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Escape Key
A site navigation panel usually opens over the page content below the landmark, so pressing Escape closes it and returns focus to its disclosure control. A <details> element doesn't close on Escape by itself, so a section built from one needs the same handling as a button.
Closes on Escape, restoring focus
Reported as: Disclosure is not closed with Escape key
A site navigation panel that opens over other content must close when users press Escape, and focus must return to the disclosure control that opened it.
When there's no handler for Escape, the panel covers what users were reading and the only way out is to find the control again and activate it. When the panel closes but focus stays on a hidden link or drops to the document body, screen reader users hear nothing to say where they are.
Listen for Escape on the control and in the panel, so the key works from either. Close the panel (clear open on a <details> element, or set aria-expanded to false on a button) and call focus() on the control in the same step.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Event Listener Type
When script in a site navigation component responds to keys, it listens for keydown or keyup. The keypress event is deprecated, and browsers don't fire it for many keys, including the arrow keys, Home, End and Escape.
Avoids the keypress event
Reported as: Deprecated keypress listener
A site navigation component's key handling should use keydown or keyup, not keypress.
When a handler listens for keypress, keys the browser doesn't send through that event go unanswered, and keyboard users find the site navigation component ignoring keys it's meant to respond to.
Replace each keypress listener with a keydown listener, and read the key from event.key.
Severity: Minor
FAQ
Which WCAG success criteria do the site navigation issues relate to?
Under 1.3.1 Info and Relationships, site navigation sits in a navigation landmark and holds links, each button that opens a panel carries an aria-expanded value that's present and correct and an aria-controls that references its panel, and a disabled link or button ignores activation.
Under 4.1.2 Name, Role, Value, each part has its correct role, links and disclosure controls have accessible names, the disabled state is declared on a link or button only and one way only, no control holds another, and activating a button updates its state.
Under 2.1.1 Keyboard, every link and disclosure control can be reached with the Tab key and takes focus itself, every link in a panel can be reached, disclosure controls activate with Enter and Space, users follow links with Enter, and an open panel closes with Escape.
The rest are best practices that map to no success criterion: a named landmark kept apart from other landmarks, no menu roles, a panel role named from its disclosure control, a single aria-controls target, and a disabled control that leaves the tab order and ignores the keyboard.
Why are some site navigation issues marked as Critical and others as Minor?
Severity reflects how much an issue gets in users' way. Critical issues leave users unable to identify or reach the site's pages:
- A part without its role
- A disclosure control without a name
- A link or disclosure control that can't be reached or operated by keyboard
- An
aria-expandedvalue that's wrong or doesn't change
Serious issues mislead or strand users:
- Links outside a navigation landmark
- A link without a name
- A missing or stale
aria-expanded - A disabled state reported wrongly
- Nested controls
- A panel that doesn't close with Escape
Moderate issues weaken orientation or trust:
- Nested navigation landmarks
- A disabled link or button that still works
Minor issues cost users some extra effort:
- An unnamed landmark
- Menu roles
- An unnamed panel role
- A missing or broken
aria-controls - A disabled control left in the tab order
- Focus that lands inside a control
- A button that ignores Space
The aria-owns checks and the sanity check on where the navigation role sits carry no severity: Evinced reports them as general and sanity checks.
Related Patterns
- Link: the element each destination in the navigation landmark is built from, including how to build and disable one
- Disclosure: the disclosure control and panel that reveal each section's links
- Menu Button: a button that opens a menu of commands, for actions rather than destinations
- Menu: a set of commands that act on the page, with its own roles and arrow-key navigation
- Breadcrumb: a secondary navigation showing where the current page sits in the hierarchy
Recommended Reading
- Navigation Landmark Example | W3C ARIA Authoring Practices Guide
- Example Disclosure Navigation Menu | W3C ARIA Authoring Practices Guide
- Example Disclosure Navigation Menu with Top-Level Links | W3C ARIA Authoring Practices Guide
navigationrole | W3C WAI-ARIA<nav>: The Navigation Section element | MDN- ARIA: navigation role | MDN