iFrames
<iframe>
should include a title element inside the parent tag.As a best practice, it is good to set the scrolling to "auto" or "yes" in the
<iframe>
tag settings. This allows people with low vision to be able to scroll into content within the<iframe>
that they might not otherwise be able to see.
Focus order
- The default focus order must be logical, intuitive, and match the visual order of a page.
Tabindex
An element that is normally focusable but is in an inactive state (e.g., a disabled input box or button) should be given a negative tabindex (
tabindex="-1"
).Should add the focus back to the element when active or needed (can use JS or TS).
Should avoid positive tabindex. Giving focus to non-interactive elements and disrupting the normal focus order may confuse and frustrate the users. Rarely do circumstances warrant adding a positive tabindex, such as
tabindex=1
to a non-focusable element.
Skip links
A skip link must be included to help users bypass the navigation menu.
Skip link should includes context about the link's purpose (e.g. "Skip to main content" ) and can use additional ARIA properties like aria-labelledby, aria-label.
Skip link can be visible or visually hidden (based on design) until a user tabs to it.
Focus indicator
- Make sure that focus indicator is not hidden beneath other components.
Browser default styling
Should not override the default browser focus styling (e.g.
"outline: 0"
or"outline: none"
).Custom focus styles are allowed.
JavaScript
Trigger events
- If a click event (e.g.
onClick()
) is applied to non-semantic elements (e.g.<div>
) a keydown/keyup event must be added to detect the enter or space key press.
Page titles
- Each page should have a title. It is acceptable to use the
document.title
property or a third-party package for this purpose
Dynamic content
Possible misuse | Correct use |
---|---|
Render large chunks of non-semantic HTML | Render smaller pieces of semantic HTML |
Not allowing time for dynamic content to be recognized by assistive technology | Using a setTimeout() time delay to allow users to hear the full message |
Applying style attributes for onFocus() dynamically |
Use :focus for the related elements in your CSS stylesheet |
Applying inline styles may cause user stylesheets to not be read properly | Keep your styles in CSS files to keep the consistency of the theme |
Creating very large JavaScript files that slow down overall site performance | Use less JavaScript; prefer CSS for animations or sticky navigation for better performance |
Component level focus management
- When the user opens a modal, they should be able to navigate between the actionable elements within it (e.g., cancel and submit buttons) using the Tab key. However, the focus must remain confined to the modal, preventing the user from accessing elements outside of it unless they explicitly close the modal. This ensures that the focus is trapped within the modal.
Page level focus management
Focus must also be maintained when a user navigates from page-to-page.
Anytime a user clicks on a link to go to another page within the application, the focus is either kept in the same place or potentially placed somewhere else entirely.
Here are the suggested focus placements when the user navigates from one page to another.
Place focus on the main container with an aria-live announcement.
Put the focus back on a link to skip to the main content.
Move the focus to the top-level heading of the new page.
Component level state management
Component state should be managed using ARIA attributes (e.g. use an
aria-expanded
attribute to tell the user whether a drop-down menu or list is expanded or collapsed.).It's important to be selective when applying ARIA attributes. Think through the user flow to understand what critical information should be conveyed to the user.
Page level state management
If content is added or updated dynamically on the page (e.g., an alert message or text change), it should be announced to the user.
-
Better to use
- React: react-aria-live or react-a11y-announcer
- Angular: LiveAnnouncer
- Vue: vue-a11y-utils
(continue...)
Top comments (0)