Skip to Content
Focus Rings You Can See (And Shouldn't Remove)
Intermediate
0 likes
Tutorials

Focus Rings You Can See (And Shouldn't Remove)

Test visible keyboard focus on a link, input and working button, and distinguish focus-visible from hover and pointer focus.

A keyboard user needs to see which control will react to the next key. A hover colour cannot provide that information: the mouse pointer may be somewhere else entirely. Start with native links and controls, then make their focus indicator easy to find.

This page gives you a small keyboard route and a button that responds locally. Save the example as focus-test.html. It needs only a browser.

Run a keyboard route

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Follow the keyboard focus</title>
  <style>
    * { box-sizing: border-box; }
    body {
      margin: 0;
      padding: 16px;
      font: 1rem/1.6 system-ui, sans-serif;
      color: #080b0e;
      background: #ffffff;
    }
    main { max-width: 60rem; margin-inline: auto; }
    .demo { max-width: 32rem; }
    .demo a { color: #034bff; }
    .demo label { display: block; margin-top: 1rem; }
    .demo input, .demo button {
      font: inherit;
      padding: 0.6rem;
      max-width: 100%;
    }
    .demo :is(a, button, input):focus-visible {
      outline: 3px solid #034bff;
      outline-offset: 3px;
    }
    .demo button:hover { background: #f2f8ff; }
  </style>
</head>
<body>
  <main class="demo">
    <h1>Find the active control without a mouse</h1>
    <p><a href="#notes">Read the keyboard notes</a></p>
    <label for="reference">Reference number</label>
    <input id="reference" name="reference" autocomplete="off">
    <p><button type="button" id="check">Check locally</button></p>
    <p id="result" role="status"></p>
    <h2 id="notes">Keyboard notes</h2>
    <p>Tab moves forward; Shift+Tab moves back.</p>
  </main>
  <script>
    document.querySelector('#check').addEventListener('click', () => {
      document.querySelector('#result').textContent =
        'The example button was activated. No lookup was sent.';
    });
  </script>
</body>
</html>

The controls are a real link, an input and a real button. The status message starts empty. The button's handler changes local text and does not send the reference number anywhere.

Test before touching the mouse

  1. Reload, then press Tab until the link is focused. You should see a blue outline separated from the link by a small gap.
  2. Press Tab again to reach the reference field. Type a fictitious reference.
  3. Press Tab to reach the button. Press Space and confirm that the status message appears.
  4. Use Shift+Tab to go back. The indicator should follow the active control in reverse order.

If the browser's address bar has focus, the first Tab may not immediately reach the page. Follow the visible focus movement. Browser or operating-system keyboard-navigation preferences can also affect which controls participate.

Separate focus from focus-visible

:focus matches the element that currently has focus. :focus-visible matches when the browser decides a visible focus indicator is appropriate, using the interaction context. Keyboard navigation normally triggers it. It is not a strict synonym for “keyboard only”: a text input can need an indicator after a pointer click too.

Click the input and then the button. Compare that with tabbing. Do not write a test that requires every mouse click to remove every ring. The requirement is that keyboard position stays clear, not that pointer users must never see focus.

Reproduce a lost indicator

In DevTools, temporarily add .demo :focus { outline: none !important; }. Tab through the page again. A field border or the native button styling may still hint at focus, but the deliberate blue indicator disappears. Remove that experimental rule immediately after comparing.

If a reset stylesheet already removes outlines, replace that reset or provide a visible indicator for all affected controls. Adding only a hover shadow leaves the keyboard problem unresolved. Keep the test scoped to this local file while you diagnose it.

Check the space around the ring

An outline does not reserve layout space. A parent with clipping can hide it even when the rule is correct. Check controls near panel edges, sticky bars and scroll areas. Give the control enough room or adjust the clipping, rather than moving the ring underneath neighbouring content.

Check the ring against the actual backgrounds, including any photo or coloured panel. A visible blue line on white may disappear against another blue surface. This example is a focused interaction check, not a complete accessibility audit or a guarantee for forced-colour modes.

Add one native control

Add a select menu after the input, with its own visible label. Extend the selector to include select, then follow the full Tab route again.

Expected result: the select appears between the input and button in keyboard order and has the same deliberate ring. It should work with its native keys without a custom tabindex or click-only wrapper. If the new ring is missing, inspect the selector and any later outline rule.

For feedback after an invalid submission, continue to styling form errors.

About

Test visible keyboard focus on a link, input and working button, and distinguish focus-visible from hover and pointer focus.

Responsible
Jay P
Last Update
08/22/2026
Reading Time
4 min
Was this helpful?
​ 0 ​ 0

Comments (0)

Sign in to comment

No comments yet.