How to use CSS :focus-visible for better accessibility
Use the :focus-visible pseudo-class to style interactive elements only when accessed via keyboard, improving screen reader navigation and reducing visual clutter for mouse users.
Use the :focus-visible pseudo-class to style interactive elements only when accessed via keyboard, improving screen reader navigation and reducing visual clutter for mouse users. This guide explains how to implement this selector in modern browsers to ensure your focus indicators are visible when needed and hidden when they interfere with normal mouse usage.
Prerequisites
- A modern web browser that supports the :focus-visible pseudo-class (Chrome 84+, Edge 84+, Firefox 84+, Safari 14.1+).
- Basic knowledge of CSS selectors and the box model.
- Access to a code editor or text file to create an HTML and CSS file.
- A keyboard and a mouse to test both interaction methods.
Step 1: Create a test HTML file
Create a new file named index.html and add a simple form with input fields and buttons to test the focus states. You need distinct elements to observe how the browser handles focus visually for each interaction type.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Focus Test</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<form>
<label for="username">Username:</label>
<input type="text" id="username" name="username">
<button type="button" id="submit">Submit</button>
</form>
</body>
</html>
Step 2: Create the base CSS file
Create a file named style.css in the same directory and define the basic styling for your inputs and buttons. Set a neutral background color for the body and a standard border radius for the inputs to ensure the focus outline is the only visual change during testing.
body {
font-family: sans-serif;
padding: 2rem;
}
input, button {
padding: 0.5rem 1rem;
border-radius: 4px;
border: 1px solid #ccc;
margin-right: 1rem;
margin-bottom: 1rem;
font-size: 1rem;
}
button {
background-color: #007bff;
color: white;
border: none;
cursor: pointer;
}
Step 3: Implement the default focus style
Add a rule for the :focus pseudo-class to ensure that all inputs and buttons have a visible outline when focused by any method. This provides a baseline so that users can see where they are currently interacting, which is a requirement for WCAG compliance.
input:focus, button:focus {
outline: 2px solid #007bff;
outline-offset: 2px;
box-shadow: 0 0 0 4px rgba(0, 123, 255, 0.25);
}
Step 4: Add the :focus-visible rule
Define a specific rule for :focus-visible that applies only when the element is focused via keyboard navigation. This rule should match the :focus style exactly so that keyboard users get the same clear indication, while mouse users rely on the default browser behavior if not specified.
input:focus-visible, button:focus-visible {
outline: 2px solid #007bff;
outline-offset: 2px;
box-shadow: 0 0 0 4px rgba(0, 123, 255, 0.25);
}
Step 5: Configure default browser behavior for mouse users
Some browsers hide the default outline on mouse hover or click by default. You must explicitly restore the default outline for mouse-only interactions using the :focus:not(:focus-visible) selector. This ensures that mouse users still see the standard browser outline, which is often more subtle and less intrusive than the custom one you defined.
input:focus:not(:focus-visible),
button:focus:not(:focus-visible) {
outline: 1px solid #ccc;
outline-offset: -1px;
}
Verify the installation
Open index.html in a modern browser like Chrome, Edge, or Firefox. Click the input field with your mouse; you will see the subtle default outline. Then, press Tab on your keyboard until the input is focused; you will see the thick blue outline defined in Step 4. This confirms the selector is working correctly to distinguish between mouse and keyboard interactions.
Troubleshooting
If the :focus-visible rule does not appear, ensure your browser version is 84 or newer. Older browsers ignore this pseudo-class entirely, treating it exactly like :focus. Check the browser console for errors related to unsupported CSS features, though this is rare for this specific selector.
Some users report that the focus ring disappears completely on certain operating systems or with specific browser extensions. If the outline vanishes on keyboard navigation, try disabling any accessibility extensions or themes that might override default focus styles. Ensure that your CSS file is cached or reloaded, as browser caching can sometimes serve an older version of the stylesheet that lacks the new rule.
If you are using a custom theme or a framework like Bootstrap, check if the framework defines its own :focus rules that might conflict with your :focus-visible logic. You may need to use the !important flag sparingly or scope your classes to avoid specificity wars. Always test on multiple operating systems (Windows, macOS, Linux) and multiple browsers to ensure consistent behavior across the web.
Finally, verify that the focus indicator is large enough to be seen. If the outline is too thin or low contrast, adjust the outline-width or box-shadow properties. A minimum width of 2px and a high contrast color against the background are recommended to meet accessibility standards.