--- stage: none group: unassigned info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/development/development_processes/#development-guidelines-review. title: Accessibility best practices --- ## Quick summary Since [no ARIA is better than bad ARIA](https://w3c.github.io/aria-practices/#no_aria_better_bad_aria), review the following recommendations before using `aria-*`, `role`, and `tabindex`. Use semantic HTML, which has accessibility semantics baked in, and ideally test with [relevant combinations of screen readers and browsers](https://www.accessibility-developer-guide.com/knowledge/screen-readers/relevant-combinations/). In [WebAIM's accessibility analysis of the top million home pages](https://webaim.org/projects/million/#aria), they found that "ARIA correlated to higher detectable errors". It is likely that misuse of ARIA is a big cause of increased errors, so when in doubt don't use `aria-*`, `role`, and `tabindex` and stick with semantic HTML. ## Enable keyboard navigation on macOS By default, macOS limits the tab key to **Text boxes and lists only**. To enable full keyboard navigation: 1. Open **System Preferences**. 1. Select **Keyboard**. 1. Open the **Shortcuts** tab. 1. Enable the setting **Use keyboard navigation to move focus between controls**. You can read more about enabling browser-specific keyboard navigation on [a11yproject](https://www.a11yproject.com/posts/macos-browser-keyboard-navigation/). ## Quick checklist - [Text](https://design.gitlab.com/components/text-input#accessibility), [textarea](https://design.gitlab.com/components/textarea#accessibility), [select](https://design.gitlab.com/components/select#accessibility), [checkbox](https://design.gitlab.com/components/checkbox#accessibility), [radio](https://design.gitlab.com/components/radio-button#accessibility), [file](#form-inputs-with-accessible-names), and [toggle](https://design.gitlab.com/components/toggle#accessibility) inputs have accessible names. - [Buttons](#buttons-and-links-with-descriptive-accessible-names), [links](#buttons-and-links-with-descriptive-accessible-names), and [images](#images-with-accessible-names) have descriptive accessible names. - Icons - [Non-decorative icons](#icons-that-convey-information) have an `aria-label`. - [Clickable icons](#icons-that-are-clickable) are buttons, that is, `` is used and not ``. - Icon-only buttons have an `aria-label`. - Interactive elements can be [accessed with the Tab key](#support-keyboard-only-use) and have a visible focus state. - Elements with [tooltips](https://design.gitlab.com/components/tooltip#accessibility) are focusable using the Tab key. - Are any `role`, `tabindex` or `aria-*` attributes unnecessary? - Can any `div` or `span` elements be replaced with a more semantic [HTML element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element) like `p`, `button`, or `time`? ## Provide a good document outline [Headings are the primary mechanism used by screen reader users to navigate content](https://webaim.org/projects/screenreadersurvey8/#finding). Therefore, the structure of headings on a page should make sense, like a good table of contents. We should ensure that: - There is only one `h1` element on the page. - Heading levels are not skipped. - Heading levels are nested correctly. ## Provide accessible names for screen readers To provide markup with accessible names, ensure every: - input has an [associated `label`](#examples-of-providing-accessible-names). - button and link have [visible text](#buttons-and-links-with-descriptive-accessible-names), or `aria-label` when there is no visible text, such as for an icon button with no content. - image has an [`alt` attribute](#images-with-accessible-names). - [chart has a long and short description](https://www.w3.org/WAI/tutorials/images/complex/). - `fieldset` has `legend` as its first child. - `figure` has `figcaption` as its first child. - `table` has `caption` as its first child. Remember that an [`alt` attribute](#images-with-accessible-names) should not be longer than approximately 150 characters. While there's no official guidelines on the length, some screen readers will not read longer strings inside the `alt` attribute. An accessible name can be provided in multiple ways and is decided with [accessible name calculation](https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#name_calculation). Here is the simplified order of different techniques taking precedence: 1. `aria-labelledby` 1. `aria-label` 1. `alt`, `legend`, `figcaption` or `caption` 1. `title`. ### Examples of providing accessible names The following subsections contain examples of markup that render HTML elements with accessible names. Note that [when using `GlFormGroup`](https://bootstrap-vue.org/docs/components/form-group#accessibility): - Passing only a `label` prop renders a `fieldset` with a `legend` containing the `label` value. - Passing both a `label` and a `label-for` prop renders a `label` that points to the form input with the same `label-for` ID. #### Form inputs with accessible names Groups of checkboxes and radio inputs should be grouped together in a `fieldset` with a `legend`. `legend` gives the group of checkboxes and radio inputs a label. If the `label`, child text, or child element is not visually desired, use the class name `gl-sr-only` to hide the element from everything but screen readers. File input examples: ```html ``` #### Images with accessible names Image examples: ```html ``` #### Buttons and links with descriptive accessible names Buttons and links should have accessible names that are descriptive enough to be understood in isolation. ```html {{ __('Submit') }} {{ __('page') }} {{ __('Submit review') }} {{ __("GitLab's accessibility page") }} ``` ## Role In general, avoid using `role`. Use semantic HTML elements that implicitly have a `role` instead. | Bad | Good | | --- | --- | | `
` | `