Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WNMGDS-2694] Audit ARIA on generic roles #2978

Closed
wants to merge 3 commits into from

Conversation

zarahzachz
Copy link
Collaborator

WNMGDS-2694

Added notes where we could review use of ARIA in components

@TiffanyPender
Copy link

TiffanyPender commented Mar 20, 2024

Hi @zarahzachz, I've included notes below for an accessibility take. Let me know if there are next steps or further discussion needed.

Alert

  • Could the component name be a little deceptive or confusing here? There are a few different relevant roles. Because these are all grouped together within the "Alert" component, would documentation alone be sufficient or could there be consideration for breaking down into sub-components? Some was captured in last year's audit of accessibility documentation.
  • role="alertdialog" could be used if alerts (messages that may be immediately important to users) also need the users attention to proceed in the workflow, or some sort of user confirmation, hence the dialog. Typically focus moves to an element in the dialog.
    • This role also needs to have an accessible name, defined with aria-labelledby or aria-label.
    • The alert dialog text should also have an accessible description, defined with aria-describedby.
    • Keyboard focus should be managed. Tabindex would be appropriate here.
    • aria-modal="true" is another relevant attribute here. It indicates that the presence of a "modal" element precludes usage of other content on the page.
    • aria-controls attribute would be relevant in scenarios where an "alertdialog" is triggered by an interactive element. For example, when confirming that a user is about to delete something after clicking a button.
  • role="status" is a type of live region (regions that get updated as the result of an event) whose content is important, but not critical enough to justify a role of "alert".
    • role="alert" is a specialized form of the "status" role, and is typically for messages that may be immediately important to users. It's for elements/content that's injected into the page. It's not required to set or manage focus to an alert in order for it to be processed. I've seen these used on the Marketplace as success messages, error messages, etc.
  • role="region" typically contains content relevant to a specific purpose and that is sufficiently important that users will likely want to be able to navigate to it easily. It's a generic landmark role. This may be valid for "Alert" styled components that are already on the page, but are deemed significant.
    • This role also needs to have an accessible name, defined with aria-labelledby or aria-label.
  • aria-describedby attribute can be used on each to describe the content.

Autocomplete

  • aria-selected="false" is implied with role="option", so this seems like it could be removed.

Choice List, Date Field, Dropdown, Month Picker

  • W3C suggests that the aria-invalid state is deprecated as a global state in ARIA 1.2, and that in future versions it will only be supported on specific roles. Choice list, Date Field, and Month Picker use a <fieldset> where role="group" is implied, and not one of the included supported roles. May need to pursue recommendations on how to move forward with these.
    • Dropdown - aria-invalid is supported on the combobox role. There is mention in the code that this caused an issue with VoiceOver interpreting selections as misspelled. Unsure if this is resolved.
    • Month Picker - the listbox role may be an option here as it's a supported role of aria-invalid.
    • [edited] Related: Fieldsets containing radiobuttons can support aria-invalid, but will need the addition of role="radiogroup" on the fieldset.
      • aria-required="true" (if needed) can also be set on fieldsets containing radiobuttons.

Dialog

  • tabindex="-1" may be useful for elements that should not be navigated to directly using the Tab key, but need to have keyboard focus set to them. An example includes elements in a modal that should be focused when it comes into view. It seems that our component has a wrapping div that's an immediate child to the <dialog> element, and that is where a tabindex appears. Could this be consolidated and autofocus attribute used on dialog element?
  • role="document", may be related to an issue found when working with screen readers or if role="application" is present on a parent, referenced in Bootstrap issue 30687 (possibly related, may no longer be necessary)
  • Dialog heading - I can see the argument for either use of an H1 or H2. Assuming there is already an H1 on the page, H2 may make sense since the dialog is a child of the main content. H1 could also make sense since one could argue dialogs are self-contained content on their own. I would lean towards using an H2, keeping in mind that it should be consistent across the site.
  • role="main" on <main> element - it's recommended to opt for the semantic HTML over using ARIA. The role="main" is implied with the <main> element.

Drawer

  • Same note as "dialog" about tabindex here.
  • aria-labelledby shouldn't be used on role=generic - correct, as this seems to be added to the immediate child div element of the dialog element. It's recommended to use the aria-labelledby attribute on the dialog element directly. (Same would apply for the Dialog component.)

Tab, Tab Panel

  • W3C suggests that the aria-disabled state is also deprecated as a global state in ARIA 1.2, and that in future versions it will only be supported on specific roles. The tab role is supported, but not tabpanel. Is there a use case for having tabs disabled? Typically it's not recommended to disable interactive elements as it can confuse some users.

// 🥑
// https://www.w3.org/TR/wai--1.2/#group
// - "aria-invalid (state) (deprecated on this role in ARIA 1.2)"

return (
<fieldset
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Add role="listbox" as possible remediation of deprecated aria-invalid attr on group roles.


// 🥑
// https://www.w3.org/TR/wai-aria-1.2/#button
// - "aria-invalid (state) (deprecated on this role in ARIA 1.2)"
'aria-invalid': invalid,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Investigate if role="combobox" still causes issues for VO as remediation for aria-invalid deprecation. May need further exploration if combobox still has issues.

// 🥑
// https://www.w3.org/TR/wai-aria-1.2/#option
// - "Default for aria-selected is false."
// Could remove `aria-selected="false"` from the `li` element.
export function renderStatusMessage(message: ReactNode) {
return (
<li aria-selected="false" className="ds-c-autocomplete__menu-item-message" role="option">
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Remove aria-selected attr as false is implied by its role.

@@ -139,6 +139,9 @@ export const ChoiceList: React.FC<ChoiceListProps> = (props: ChoiceListProps) =>
});

return (
// 🥑
// https://www.w3.org/TR/wai-aria-1.2/#group
// - "aria-invalid (state) (deprecated on this role in ARIA 1.2)"
<fieldset
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: If choice is radio, set role="radiogroup"

// Is `tabIndex` necessary here? It's not clear why it's being set to -1.
// It's also not clear why the `role` attribute is being set to `document`.
// Should this allow for more flexible heading tags? Locked into `h1` for now.
// Can we remove `role="main"` from the `main` element?
return (
<NativeDialog
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO:

  1. Replace tabIndex with autofocus attr
  2. Replace <h1> with <h2>
  3. Remove role="main"
  4. Apply aria-labelledby to dialog and not div

I don't believe the Bootstrap issue exists on native dialog elements, so I don't believe the role="document" is needed. Will experiment with removing this role.

@@ -69,6 +69,9 @@ export const Drawer = (props: DrawerProps) => {

const Heading = `h${props.headingLevel}` as const;

// 🥑
// Why is `tabIndex` needed here?
// `aria-labelledby` not allowed on `role="generic"` element
return (
<NativeDialog
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO:

  1. Explore replacing tabindex with autofocus
  2. Apply aria-labelledby to dialog and not div

@@ -79,6 +79,9 @@ export const Tab = forwardRef((props: TabProps, ref: any) => {
{props.children}
</a>
) : (
// 🥑
// https://www.w3.org/TR/wai-aria-1.2/#generic
// - "aria-disabled (state) (deprecated on this role in ARIA 1.2)"
<span aria-disabled="true" {...sharedTabProps}>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't realize the {...sharedTabProps} included role="tab". Disregard.

@@ -41,6 +41,9 @@ export const TabPanel = (props: TabPanelProps) => {
const classes = classnames('ds-c-tabs__panel', props.className);

return (
// 🥑
// https://www.w3.org/TR/wai-aria-1.2/#tabpanel
// - "aria-disabled (state) (deprecated on this role in ARIA 1.2)"
<div
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Explore purpose of disabled Tabs. It's recommended not to disable interactive elements as it can confuse users.

aria-disabled is deprecated on tabpanel roles. Need to figure out purpose of disabling component before mitigation can be decided.

@zarahzachz zarahzachz closed this Apr 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants