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:

  1. Use reactstrap;
  2. Use HTML semantic tags;
  3. 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 have aria-labelledby attribute, with the ids of the following elements, separated by a blank space. It should also have a role="img";
  • As the first child of <svg>, add <title> with an id 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 an id.
<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>

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