0
votes

I need a toggle button with different icons per state. The icon button looks like this:

<button type="button" role="button" aria-pressed="false">
    <svg class="icon">...</svg>
    <span>Disabled</span>
</button>

What is the better solution from an accessibility point of view if I want to change the icon (<svg>)?

  1. to have a button with two svg icons, while one is display: none depending on aria-pressed state

  2. to have a button with one svg icon that gets replaced onclick

  3. something else

1
Once the button is clicked, I assume you are doing something on the page. If this is the case, you probably need to announce something has changed on the page or focus on the changed element, and if this is the case, i don't think it matters what you do with the button because by the time the user navigate back, the button would have changed no matter by what means. I am more worried about the text in the button at this time - Huangism
I understead your first statement. I was more referencing eventual problems because there are two <svg> icons at the same time present in the dom (although not visible) or similar. What problem do you see with the text? Prototypical usecase would be an toggling text from "disable" to "enable" and back. - Sebastian Barth
I don't understand why the icons would be an issue since only one will be present at a time. The text of the button need to describe what the button is for and "click me" doesn't really say anything but I know this is probably just placeholder. For your buttons, you can either have descriptive text or aria label to tell the user what it is for - Huangism
Do your SVG icons contain any textual information about what this button does? If not, they should probably get role="presentation" to begin with. - CBroe

1 Answers

2
votes

The simplest solution to this is to not rely on the SVGs at all from an accessibility standpoint.

So for both of them you would use aria-hidden="true" and role="presentation" (as support can be flaky for each in older screen readers).

As you can probably tell I am suggesting having two icons and swapping them out with display:none on one or the other, or better yet why not get fancy and transition between states.

Note it doesn't matter from an accessibility standpoint (as we are hiding them from screen readers) whether you use two images or use one and swap them out with JavaScript, it is just easier to maintain if the icons are within the DOM, rather than having ugly SVG markup in your JavaScript.

You already have some text within the button that says 'disabled' which I am assuming will change to 'enabled' depending on the button state.

At this stage all you need to do is add some visually hidden text (see the CSS below to hide something visually but still allow it to be accessed by the screen reader) explaining the button function.

So if this button was to enable dark theme you would add some visually hidden text to explain the purpose of the button.

Putting that all together you would get something along the lines of:-

<button type="button" role="button" aria-pressed="false">
    <svg class="icon active" aria-hidden="true" role="presentation" focusable="false">...</svg>
    <svg class="icon hidden" aria-hidden="true" role="presentation" focusable="false">...</svg>
    <span class="visually-hidden">Dark Theme </span><span class="state-toggle">Disabled</span>
</button>

Visually Hidden CSS

.visually-hidden { 
    position: absolute !important;
    height: 1px; 
    width: 1px;
    overflow: hidden;
    clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
    clip: rect(1px, 1px, 1px, 1px);
    white-space: nowrap; /* added line */
}

You will see I added a class "state-toggle" to the <span> you will be toggling from "disabled" to "enabled" just to make it clear, the 'visually-hidden' text should never change. Also note the space after "Dark Theme" to ensure it is read correctly.

I also added 'active' and 'hidden' classes to the two SVGs, obviously you would be better just having one class of 'active' or 'hidden' and default to a state but it was for demonstration purposes.

Also note I added focusable="false" to the SVG as otherwise Internet Explorer may make the SVG focusable due to a bug.

A final consideration is that aria-pressed also has flaky support and you appear to be creating a 'toggle' (albeit with different icons instead of a switch).

What you are doing is perfectly valid and should work but you may consider using a checkbox instead.

Read this in-depth article on different ways to implement toggles written by Hayden Pickering as it provides lots of insights into screen reader behaviour and workarounds for WAI-ARIA support issues / WAI-ARIA fallbacks.