Translating design to accessible front-end code
Tags: a11y, webdev, html
Published: 2021-02-01 12:48:16

A picture speaks a 1000 words, but sometimes a design lacks details on how something should function for screen readers. It is up to the developer to fill in these gaps. I will be looking at how to translate this design of a rating scale question into accessible front-end code and avoid traps that can lead to frustrated screen reader users.

![UI to rate on a scale of 1-5 whether one agrees that "Tomatoes are fruits"](https://dev-to-uploads.s3.amazonaws.com/i/dv742fqdlztztnfmoc32.png)

## Functionality over aesthetics

Looking at the design, which HTML tag do you think should be used for the options? 

1. `<button>`
2. `<button aria-pressed="false">`
3. `<input type="radio">`
4. `<input type="checkbox">`

...

...

...

I added some space to avoid spoilers

...

...

...


Yes, you guessed it; `<input type="radio">` would be best suited. While the design shows elements that look like buttons, we need to consider functionality. Given this question is for rating something, we know that only one option should be selected at a time, so we need a group of interlinked elements that are aware of other members' state. Not only do radio buttons work in a group, but they also only allow the selection of one option at a time. Because it's such a common UI solution, users with screen readers know that selecting an option will deselect the previous selection even though screen readers may not announce the deselection. 

![Radio buttons with default disc styling](https://dev-to-uploads.s3.amazonaws.com/i/btmvk0pb54vfl4g9mp5j.png)

But radio buttons don't look like the design. How can we achieve both the design for visual users and functionality for users with screen readers? We can simply hide the inputs from visual users and style the label to look like a button. 

```css
/* "display: none;" hides things from screen readers and visual users.
The following css hides content but 
still make it accessible to screen readers */
.visuallyHidden {
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  height: 1px;
  width: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
}
```

```jsx
<input class="visuallyHidden" type="radio" id="option1">
<label class="buttonStyle" for="option1">
   1
</label>
```

## Unseen, but not unspoken

It may be obvious to visual users that the options are on a scale, but it's not as clear to users with screen readers. How can we clarify this? (I have simplified the code to make it easier to read so we can concentrate on the core question)

1. Add more instructions to the question
```html
<legend>Tomatoes are fruits 
    <!-- additional instructions that 
    are visually hidden -->
    <span class="visuallyHidden">Please rate on a scale of 1 to 5, where 1 is strongly disagree and 5 is strongly agree</span>
</legend>
<input class="visuallyHidden" type="radio" id="option1">
<label class="buttonStyle" for="option1">
   1
</label>
<!--
   repeat for 
   2
   3
   4
   5
-->
<div aria-hidden="true">
   <span>Strongly disagree</span>
   <span>Strongly agree</span>
</div>
```

2. Add more visually hidden labels to the radio buttons
```html
<legend>Tomatoes are fruits</legend>
<input class="visuallyHidden" type="radio" id="option1">
<label class="buttonStyle" for="option1">
   1
   <!-- additional label that 
    is visually hidden-->
   <span class="visuallyHidden"> Strongly disagree</span>
</label>
<!--
   repeat for 
   2 disagree
   3 neutral
   4 agree
   5 strongly agree
-->
<div aria-hidden="true">
   <span>Strongly disagree</span>
   <span>Strongly agree</span>
</div>
```
...

...

...

I added some space to avoid spoilers

...

...

...

Yes, that's right you can use both. The first option makes use of visually hidden text in the legend. This clarifies the question and we can hide the labels below the radios. The second method is to add visually hidden labels to all the options and then hide the redundant labels below the radios. I would lean toward the first option because the second option requires more copy and translation work to function with different scales e.g. on a scale of excellent to poor. 

{% codepen https://codepen.io/katherine_hoang/pen/ExNaKzG %}

## Conclusion 

The challenge and fun of taking a design and translating it into accessible front end code is thinking about how to best achieve functionality and aesthetics. I've mentioned some of the thinking that goes into this, but please note there are other aspects of a11y that have not been covered in this article such as focus and keyboard inputs.