9.3 KiB
Accessibility
General Practices
As a general rule, accessible software is achieved by following web development best practices. As Treeherder uses the reactstrap library, it is recommended to use one of its components, if possible.
If you can not find a suitable component, prefer HTML5 semantic tags and avoid using generic tags, such as span
and div
. Moreover, try to use more headings (h1
to h6
) whenever possible, because screen readers users usually navigate by headings and that is only possible when developers insert them in the code.
If you can build your layout neither with reactstrap nor with semantic tags, please insert aria-role
in them. There are examples of how to use aria-role
in: Tables, Progress Bar, List.
aria-role
is important because it gives meaning to the generic HTML tag. That gives some direction to screen readers on which functionalities to provide and some information to users.
In summary, implement your layout trying to use these in the following order:
- Use reactstrap;
- Use HTML semantic tags;
- Use
aria-role
attributes.
Font Awesome
Treeherder also uses the Font Awesome
library for some icons. Usually, there is no need to insert an additional explanation to them. However, if the icon has a semantic meaning, you can insert it by adding a title
prop in the FontAwesomeIcon
component.
<FontAwesomeIcon icon={icon} title="Icon description" />
Colors
Treeherder uses Bootstrap color utility classes. A few colors were modified in order to meet WCAG standards for color contrast.
Please use this custom color according to the following table:
Bootstrap Color | Treeherder Color |
---|---|
btn-info |
btn-darker-info |
text-info |
text-darker-info |
btn-secondary |
btn-darker-secondary |
text-secondary |
text-darker-secondary |
For example, if inserting a text color into an element, use className="text-darker-info"
, instead of using className="text-info"
.
In some reactstrap components, you can insert a prop
specifying its color. In that case, you use only the color name, without its prefix.
Component prop color |
---|
darker-info |
darker-secondary |
For example:
<Button color="darker-info">
Info colored button with contrast passing score
</Button>
Known reactstrap components that accept the color
prop and work with custom Treeherder colors: Badge
, Button
, Card
, DropdownToggle
, FormText
, NavBar
, Progress
, Spinner
.
In case you need to add more custom colors, please add on treeherder-custom-styles.css style sheet.
Inserting new colors
If you add new colors to the style sheets, please make sure the text and background color combination passes the minimum contrast ratio defined by WCAG.
In order to check if it passes, you can use WebAIM contrast checker or use Firefox's Accessibility Devtools.
Red and Green
Red and green colors are not very noticeable for some types of color deficiency. For that reason, it is recommended to insert an accompanying icon, such as a checkmark (for success) or an exclamation point (for warning or error).
For that task, FontAwesome
is a supported choice.
Images
Image HTML tag
If you add an image, make sure you also write an alternative text for it. The text should be descriptive and support the screen reader user.
<img src={image} alt="A description of the image">
If you are not sure how to write this, please refer to this guide.
SVG
For SVG images, do the following:
<svg>
should havearia-labelledby
attribute, with the ids of the following elements, separated by a blank space. It should also have arole="img"
;- As the first child of
<svg>
, add<title>
with anid
attribute. The content of this element should be the title of the image; - (Optional) Following
<title>
, you can add<desc>
, which describes the image. You should also add anid
.
<svg aria-labelledby="imageTitle imageDesc" role="img">
<title id="imageTitle"> A title of this image </title>
<desc id="imageDesc"> A description of this image </desc>
// ...
</svg>
If your case is more specific, please check this guide.
Interactive elements
When creating elements that have event listeners, prefer any component of the reactstrap interactive elements. Examples are: Button
, Input
, DropdownToggle
. You can also choose a HTML <a>
element.
If you need to insert an event listener in a non-interactive element, such as a span
, add also an aria-role
of button
, link
, checkbox
, or whatever seems closer to the functionality of the element.
<span onClick={someFunction} aria-role="button">
Unconventional button
</span>
Dropdown menu
There is a special case when you are creating a dropdown menu. First of all, try to follow reactstrap structure.
Lastly, insert an additional tag prop
to DropdownItem
component.
<DropdownItem tag="a"> Menu Item </DropdownItem>
Forms, inputs and buttons
Apart from inserting high color contrast combinations in buttons, also make sure it has a :focus
style (usually a blue outline is enough). If you use reactstrap's Button
component, this is added by default, hence it is recommended.
In case the content of the button is not a text (an icon or graphical element, for example), this element should have an aria-label
, explaining what it does.
<Button aria-label="Bookmark alert 12345" onClick={onClickFunction}>
<FontAwesomeIcon icon={icon} />
</Button>
For input and checkbox, those are important to be labeled - placeholders are not enough for screen reader users. For example, when inserting an email input and a checkbox, using reactstrap, the structure should be:
<Form>
<FormGroup>
<Label for="email">Email</Label>
<Input
type="email"
name="email"
id="email"
placeholder="Insert your email"
/>
</FormGroup>
<FormGroup>
<Label check>
<Input type="checkbox" /> I agree with the terms
</Label>
</FormGroup>
</Form>
If in doubt, please check the reactstrap Form documentation.
Specific elements
Progress Bar
Across Perfherder, there are some Progress Bars, which are built using reactstrap components. There is still an issue, however, when adding labels on each bar. While this is still not solved, it is recommended to add an aria-label
in the wrapping component, explaining the values of the bar.
For example:
<Progress
multi
aria-label={`Description of progress bar. Metric: ${finalValue}`}
>
<div aria-hidden="true">
<Progress bar value={valueOne} />
<Progress bar value={valueTwo} />
</div>
</Progress>
Tables
In tables, there should always be headers.
<Table>
<thead>
<tr>
<th> First header </th>
<th> Second header </th>
<th> Third header </th>
</tr>
</thead>
<tbody></tbody>
</Table>
Also, if you are not using <table>
tag or reactstrap's Table
component to create the table, please use all the necessary role
attributes.
Alternatively, you may choose to use the React Table library. The only requirement here is to insert a role="table"
, like this:
<ReactTable
getTableProps={() => ({ role: 'table' })}
/>
Other Components (Third-Party)
Take special care when bringing in new elements/components to the app. They should have a good documentation on accessibility and should be tested beforehand by an a11y fellow.
References
- WAI-ARIA Authoring Practices is the official document that covers specific cases for creating accessible web applications.
- Auditing For Accessibility Problems With Firefox Developer Tools is a guide on how to use the Accessibility tab in Firefox Devtools.
- Accessibility Inspector is the official documentation for Accessibility Inspector in Firefox Devtools.