Skip to content

Accessibility Project

Operable

User interface components and navigation must be operable.

Everybody should be able to use a site, regardless of their individual accessibiliy needs. This might mean not having access to a computer mouse, or having enough time to read and use the content.

Clickable Area

Users also need enough space on screen when clicking on things. There are two WCAG criteria for this, a minimum requirement and an enhanced option:

Target Size (Minimum)

The size of the target for pointer inputs is at least 24 by 24 CSS pixels, except where:

  • Equivalent. The function can be achieved through a different control on the same page that meets this criterion;
  • Inline. The target is in a sentence or its size is otherwise constrained by the line-height of non-target text;
  • User Agent Control. The size of the target is determined by the user agent and is not modified by the author;
  • Essential. A particular presentation of the target is essential or is legally required for the information being conveyed.

Target Size (Enhanced)

The size of the target for pointer inputs is at least 44 by 44 CSS pixels except when:

  • The target is available through an equivalent link or control on the same page that is at least 44 by 44 CSS pixels;
  • Inline. The target is in a sentence or block of text;
  • User Agent Control. The size of the target is determined by the user agent and is not modified by the author;
  • Essential. A particular presentation of the target is essential to the information being conveyed.
A younger woman is showing a mobile phone to an older woman.

Example: Clickable Area

I have an info box component on my React site that can be closed by clicking the cross in the corner.

.cross {
border: solid 1px rgb(194, 65, 12);
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
margin-left: auto;
}
.cross:hover {
background-color: rgb(194, 65, 12);
color: white;
}
<div>
<div
className="cross"
onClick={handleClick}
aria-label="Close"
>
X
</div>
<p>Lorem ipsum dolor sit amet.</p>
</div>

Here's my component. I've added buttons to change the clickable area. Compare the different sizes, which one seems the easiest to click?

Also, note the added aria-label that adds information to the symbol.

X

Lorem ipsum dolor sit amet.

I want my site to be as accessible as possible, so I think the enhanced size is appropriate. Let's add some CSS:

.cross {
border: solid 1px rgb(194, 65, 12);
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
margin-left: auto;
height: 44px;
width: 44px;
}

Note that while the minimum requirement is a height and width of 24 px, I think most would agree that the larger size of at least 44 px is more usable as well as being more accessible.

Using a Keyboard and Focus Order

There is a WCAG criterion stating that users should be able to navigate and interact with a site using only a keyboard.

Keyboard

All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints.

To interact with links, buttons, and other elements using only a keyboard, users can navigate through a site by tabbing, following what's known as the focus order. This may not be apparent to those who interact with a site using a mouse or touch, and it is one of the most common sources of accessibility issues.

Focus Order

If a Web page can be navigated sequentially and the navigation sequences affect meaning or operation, focusable components receive focus in an order that preserves meaning and operability.

Example: Test the Focus Order on My Site

Here's an example site you can use to test the focus order by tabbing through all elements that can be interacted with (usually this means elements that can be clicked on with the mouse pointer or by using the enter key).

The following code is a bit stripped down but demonstrates the basic structure of the site, which is what we are interested in here. The only relevant CSS is that the dialog box has position: absolute and some styling to put it roughly in the middle of the site.

const [showDialog, setShowDialog] = useState(false);
<h1>Example Focus Order Site</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
<hr></hr>
<main>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Laboriosam, eius.
</p>
<label
id="dropdownLabel"
htmlFor="dropdown"
>
Choose an option:
</label>
<select id="dropdown"
<option value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
<option value="Option 3">Option 3</option>
</select>
<button
onClick={() => setShowDialog(true)}
>
Open Dialog
</button>
{showDialog && (
<div>
<p>Example Message</p>
<button
onClick={() => setShowDialog(false)}
>
Close
</button>
</div>
)}
</main>
<hr></hr>
<footer>
<a href="mailto:example@mail.com">Email me!</a>
</footer>

You can bring the focus to the Home link with the button at the top. Move focus by using tab on your keyboard, the element will get an orange background.

Clicking the "Open Dialog" button will open a dialog box.

Example Focus Order Site

Lorem ipsum dolor sit amet consectetur adipisicing elit. Laboriosam, eius.


Focus will shift to the next element in the focus order, further down in the code. However, sometimes you might have a popup or module that you want to give focus after a certain action.

Take the dialog box from the example above: In order to ensure that the focus shifts to the "Close" button after the "Open Dialog" button, it needs to be the next interactable element in the code.

However, since the box is styled with position: absolute it could be put somewhere else. Here's an example where the box is positioned at the top within the <main> element instead:

Example: Unpredictable Focus Order

<main>
{showDialog && (
<div>
<p>Example Message</p>
<button
onClick={() => setShowDialog(false)}
>
Close
</button>
</div>
)}
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Laboriosam, eius.
</p>
<label
id="dropdownLabel"
htmlFor="dropdown"
>
Choose an option:
</label>
<select id="dropdown"
<option value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
<option value="Option 3">Option 3</option>
</select>
<button
onClick={() => setShowDialog(true)}
>
Open Dialog
</button>
</main>
<hr></hr>
<footer>
<a href="mailto:example@mail.com">Email me!</a>
</footer>

A user with a mouse or touch screen would not notice any difference, but a user that is tabbing through the focus order will notice that the next element to get focus after the "Open Dialog" button would not be the "Close" button. Instead, it would be the "Email me!" link in the <footer>, forcing the user to tab all around the site until focus finds the "Close" button.

A woman is visibly frustrated in front of her computer.

Changing the Focus Order

Finally, let's take a look at how you can change the focus order if necessary.

Example: Changing the Focus Order

There are a couple of methods to alter the focus order. The tabindex attribute can be used to decide the exact sequential order of the focus as 1, 2, 3 and so on. It can also make any element focusable, even if a user can't interact with it.

<nav>
<a href="/" tabIndex={1}>Home</a>
<a href="/about" tabIndex={2}>About</a>
<a href="/contact" tabIndex={3}>Contact</a>
</nav>
<p tabIndex={4}>This element is not clickable but will recieve focus.</p>

Note that in React, the attribute uses camel case, tabIndex.

As a default, elements without a specified tab index have an index of 0 and will shift to the next clickable element in the code structure as we've looked at above. Using a negative tab index will remove elements from the focus order and render them impossible to reach with focus.

MDN recommends avoiding using a tabindex with a value above 0, and if used it must follow the relationships in the content.

You can also use the ref tag and the focus() method to move the focus directly to another element. Here's an example where I keep the dialog box above the button that opens it in the code.

I add a ref tag to the "Close" button, allowing me to target it. To shift the focus I add a focus() method within a useEffect that listens to the showDialog state.

This way the dialog box will open and focus will shift to the "Close" button:

const [showDialog, setShowDialog] = useState(false)
const closeBtnRef = useRef(null)
useEffect(() => {
if (showDialog && closeBtnRef.current) {
closeBtnRef.current.focus()
}
}, [showDialog])
<main>
{showDialog && (
<div>
<p>Example Message</p>
<button
ref={closeBtnRef}
onClick={() => setShowDialog(false)}
>
Close
</button>
</div>
)}

Example Altered Focus Order Site


Lorem ipsum dolor sit amet consectetur adipisicing elit. Laboriosam, eius.


A few notes:

The next element in the focus order after the "Close" button is the dropdown <select>, which probably will be confusing for a user. This is not desirable since the focus order should be predictable and easy to understand.

While using the ref tag and the focus() method can come in handy, it's a good idea to use them sparingly. Aim to set up your site so that the focus order is straightforward and easy to follow.

I'm using a non-semantic <div> for the dialog box, but you should use the <dialog> element which comes with some built in functionalty and even moves focus to the dialog automatically when opened. Read more over at MDN and consult CanIUse to find out which browser versions support the element.