How to properly set up a11y / aria props for a button input that is labelled but also changes current value?

170 Views Asked by At

So let's say you have:

  • a button that controls time period
  • the button opens a dialog to select the time period
  • the button changes text base on the selection (ie "3 days", "1 week", etc)

I want to label the button, but if I add aria-label="time period" to the button, then the current value (ie "3 days") is never read, since the aria-label overrides any current text.

So what is the best solution for both labelling the button, and indicating its current value, to a screenreader?

2

There are 2 best solutions below

0
slugolicious On

Sounds like the misuse of a button. You want it to indicate some action and you want it to display a value. That's not what a button is for. It should perform an action.

The value of the time period should be a separate DOM element. Perhaps plain text with a label.

<p id="foo">Time period: 3 days</p>
<button aria-describedby="foo">Change time period</button>

When a screen reader user tabs to the button, they'll hear "Change time period, button, time period: 3 days".

Note, however, that aria-describedby specifies the description of the element and the user could turn off description announcements (sometimes called hints) in the screen reader, in which case they wouldn't hear the time period value, although they could navigate back up to the time period using other screen reader keyboard shortcuts.

0
QuentinC On

As @slugolicious says, this is basically a misuse of buttons. A button is always supposed to contain its own label, and hasn't any additional value beyond that label, because a button normally just performs a given fixed action.

As you have well observed, the label must contain everything. You may write aria-label="Time period: 3 days", and dynamically change it via JavaScript as needed, it will work, but it isn't beautuful code. That's an hack. Itt may, additionally, create problem for users of voice control, who may need to say the entire label to activate the button, i.e. "Press time period three days", which is quite unnatural, and they won't be able to guess it easily if the term "time period" isn't shown on screen at all.

The best would be to use appropriate elements, that is, a <label> and an <input> or <select>, such as:

<label for="timeperiod">Time period: </label>
<select id="timeperiod">
<option value="...">3 days</option>
<option>...</option>
...
</select>

Or at least do as @slugolicious says, separate in two elements, one presenting the current value and then the button opening a popup, a menu or whatever allowing to change the value. Look at his code as an example.

If you really can't do it because your customer don't understand and is narrow-minded, you can hack the thing a little by changing the role of the button to something else. For example the following makes both the label and the text content be read. Tested with latest Chrome and Jaws.

<button type="button" role="combobox" aria-label="Time period">3 days</button>

But, again, this is an hack and ideally shouldn't be used, as it isn't guaranteed to work everywhere as desired. IN this example, I used the role combobox, telling the user that he/she can both enter a value manually or select among a list of predefined values.