RatedWithAI

RatedWithAI

Accessibility scanner

Can a keyboard reach everything a mouse can?

Enter your domain. We read the HTML your server sends and find every element a mouse can click that Tab never lands on, every focus outline switched off with nothing put back, every tabindex pulling the order out of sequence and every skip link that goes nowhere — each under the criterion it fails.

Free, instant, no signup and no card. Nothing is stored.

Free, instant, no signup and no card. We read the HTML your server sends for that one page, find everything a mouse can click, and check a keyboard can reach it. Nothing is stored.

The failure you can film in thirty seconds

Most accessibility failures are heard: a button a screen reader announces as nothing, an image with no description. A keyboard failure is felt. Someone presses Tab and focus jumps straight past the menu, the "Add to cart", the date picker — because the thing everyone else clicks is a <div> with a click handler, and a div is not in the tab order.

Keyboard users are not only blind users. They are people with tremor, RSI or paralysis, people using switch devices, mouth sticks and voice control that drives the keyboard, and anyone whose trackpad has just died. And "could not be used without a mouse" is one of the most common findings in ADA website complaints, because it needs no expertise to show — only a video of the Tab key.

The other half is seeing where you are. A site that removes the browser's focus outline because a designer disliked it on click leaves every keyboard user pressing Tab with nothing on screen moving. It is one line of CSS, usually in a reset stylesheet or a focus:outline-none class copied from a component example.

What this checker refuses to call a failure

A free checker that a stranger runs on their own site has exactly one way to be useless, and it is to cry wolf. So two things are called failures here, both under SC 2.1.1 at level A, and both are something that acts like a control and cannot be reached. Everything else is reported, argued, and kept out of the count.

The card pattern is fine. A clickable card with a real link inside gives a keyboard user the same destination through the link. So does a clickable span inside a button. Neither is reported. A click handler on an empty element — a modal backdrop — is not a control, and Escape is the keyboard route to the same result.

Roving tabindex is fine. In a tab bar, a menu or a radio group only one item is in the tab order and the arrow keys move between the rest, so role="tab" tabindex="-1" is correct and is never counted.

A hidden element is not a missing one. Subtrees behind hidden, inert, aria-hidden or display: none are skipped — but Tailwind's hidden md:flex is a desktop menu, visible on a laptop, and it is read.

We tested this against more than forty home pages before shipping it, including Apple, Stripe, GitHub, GOV.UK, Airbnb, Yahoo and Squarespace. Every pattern above came from one of those reads, and each is now a fixture the checker is re-tested against on every deploy.

What the checker looks for

Two failures, then the review and verify items — real problems that WCAG does not forbid outright, or that cannot be proved from served markup, reported separately and never counted as violations.

Clickable, but a keyboard can never reach itFailureSC 2.1.1 Keyboard (Level A)
The element has a click handler written into its markup — onclick, @click, x-on:click, ng-click, a Stimulus click action or an htmx request — but it is a div, span, li, tr or similar, which is not in the tab order. A mouse user clicks it; a keyboard user presses Tab straight past it and never learns it does anything. Nothing inside it is focusable either, so there is no second route to the same action.
The fix: Make it the element it is acting as: a `<button type="button">` for an action, an `<a href>` for navigation. Both are focusable and fire on Enter (and Space, for a button) with no extra code. If it has to stay a div, it needs all three of `tabindex="0"`, a `role`, and a keydown handler for Enter and Space — which is exactly what the button gives you for free.
Says it is a control, but a keyboard can never reach itFailureSC 2.1.1 Keyboard (Level A)
The element tells assistive technology it is a button, link, checkbox or switch through its role attribute, but it is not natively focusable and has no tabindex. A screen reader user hears "button" while browsing and cannot operate it; a sighted keyboard user never lands on it at all. A role changes what an element is called. It does not make it focusable, and it does not make it respond to keys.
The fix: Replace it with the native element — `<button>`, `<a href>`, `<input type="checkbox">`. Otherwise add `tabindex="0"` and handle Enter (and Space, for a button, checkbox or switch) in a keydown listener.
Focus indicator switched off, with nothing put backReviewSC 2.4.7 Focus Visible (Level AA)
The page's own CSS or its utility classes remove the outline a browser draws around whatever has keyboard focus — `outline: none` in a :focus rule, an inline style, or Tailwind's `outline-none` / `focus:outline-none` — and the same rule or element sets no replacement (no ring, shadow, border, background or underline). A keyboard user then presses Tab and nothing on screen moves: they are navigating blind. It is a review item rather than a failure because a stylesheet this reader does not load can restore an indicator.
The fix: Delete the reset, or scope it so it only applies to mouse clicks: `:focus:not(:focus-visible) { outline: none; }` keeps the ring for keyboard users. With Tailwind, pair every `focus:outline-none` with a `focus-visible:ring-2` (or `focus-visible:outline`).
Skip link points at nothingReviewSC 2.4.1 Bypass Blocks (Level A)
The page has a "skip to content" link — good — but no element in the served HTML has the id it points at, so pressing it does nothing and focus stays at the top. A page with a <main> landmark still meets SC 2.4.1 for screen reader users, who can jump by landmark; a sighted keyboard user cannot, and the skip link is their only shortcut. It is review because a framework can render the target after this read.
The fix: Give the main content wrapper the id the link names — `<main id="main">` for `href="#main"` — and `tabindex="-1"` if it is not itself focusable, so focus actually moves in every browser.
No way past a long headerReviewSC 2.4.1 Bypass Blocks (Level A), where there is also no landmark
A keyboard user has to press Tab this many times, on every page view, before focus reaches the main content — and there is no skip link to jump it. Landmarks and headings meet SC 2.4.1 for screen reader users, which is why this is review and not a failure, but a sighted keyboard user has no landmark navigation. The skip link is for them.
The fix: Make the first focusable element on the page `<a href="#main" class="skip-link">Skip to content</a>`, visually hidden until focused, and give the main content `id="main"`.
tabindex greater than zeroReviewSC 2.4.3 Focus Order (Level A), where it scrambles the order
A positive tabindex pulls the element to the front of the tab order, ahead of everything that does not have one, in numeric order. It is almost never what was intended: the search box with tabindex="1" is visited before the logo, the navigation and the skip link, and focus then jumps back to the top of the page. It becomes a failure when the resulting order stops matching the meaning of the page, which is a judgement about this page that only a person can make.
The fix: Use `tabindex="0"` (in order with the document) or remove it, and put the element where it belongs in the source. The DOM order is the tab order; change the markup, not the number.
Visible link or control taken out of the tab orderReview
A link, button or form field that is on screen carries `tabindex="-1"`, so Tab skips it. Sometimes that is deliberate and correct — a card whose image link and title link go to the same place, a carousel slide that is off screen — and links with a focusable twin are already excluded here. When it is the only way to reach that destination, a keyboard user cannot.
The fix: If the element is the only route to its action, remove `tabindex="-1"`. If it is a duplicate, also give it `aria-hidden="true"` so a screen reader does not announce it twice.
Double-click handlerVerify
The element responds to a double click, which has no keyboard equivalent at all. If the same action is available some other way — a button, a menu item, a key — it is fine. If double-click is the only way to do it, a keyboard user cannot.
The fix: Offer the action through a focusable control as well, or bind it to Enter on the focused element.

The two-minute manual test

The checker reads markup. This is the part only a person can do, and it needs nothing but the keyboard.

  1. Tab from the address bar. The first stop should be a skip link. Every stop after it should be visibly outlined, in an order that follows the page.
  2. Operate everything. Enter follows links and presses buttons. Space presses buttons and ticks checkboxes. Arrow keys move inside menus, tabs, radio groups and sliders.
  3. Open a dialog, then leave it. Focus should move into the dialog, Tab should stay inside it, and Escape should close it and put focus back on the button that opened it.
  4. Finish a real task. Search, add to cart, check out, submit the contact form. If any step needs the mouse, that is the finding that matters most, whatever any tool says.

Common questions

What does a keyboard accessibility checker actually check?
Whether everything a mouse can operate, a keyboard can reach. This one reads the HTML your page serves and finds elements that carry a click handler in their markup — onclick, Alpine's @click, ng-click, a Stimulus action, an htmx request — or that call themselves a button, link, checkbox or switch through role=, and that are not in the tab order. It also finds the focus indicator being switched off in your CSS or Tailwind classes, positive tabindex values that scramble the order, links taken out of the order, and skip links that go nowhere. It counts the Tab presses between the top of the page and its main content.
How do I test keyboard navigation on my website myself?
Put the mouse away and press Tab from the address bar. Every link, button and field should receive focus in an order that follows the page, and you should be able to see where focus is at every step. Enter should follow a link and activate a button; Space should activate a button and toggle a checkbox; arrow keys should move inside menus, tabs and radio groups; Escape should close a dialog and return focus to what opened it. This checker does the part that can be read from the markup in a second; the manual walk-through is the part only a person can do.
Why is a clickable div a WCAG failure?
A div or span is not focusable, so it is not in the tab order: pressing Tab moves straight past it. SC 2.1.1 Keyboard at level A requires every function to be operable through a keyboard, and a click handler on an element Tab cannot reach is a function that is not. A real <button> is focusable and fires on Enter and Space with no extra code, which is why the fix is almost always to use one.
My card is a clickable div. Is that reported?
Not when there is a real link inside it. The card pattern — a whole card clickable with the mouse, and a heading link inside it that the keyboard reaches — gives a keyboard user the same destination, so it is not a failure and this checker does not report it. It also skips click handlers on elements with no content (a modal backdrop you click to close), handlers that only send analytics, and Alpine's @click.outside, which closes things rather than activating them.
Is outline: none always a failure?
Only when nothing replaces it. SC 2.4.7 Focus Visible at level AA requires a visible focus indicator, not the browser's default one. A rule that removes the outline and adds a box-shadow, border or background change is fine; so is :focus:not(:focus-visible) { outline: none }, which hides the ring on mouse clicks and keeps it for the keyboard. This checker reports a reset only when the same rule or element puts nothing back and no :focus-visible rule on the page draws an indicator — and even then as review, because a stylesheet it did not load can restore one.
Do I need a skip link?
SC 2.4.1 Bypass Blocks at level A requires a way to skip repeated blocks of content. A <main> landmark satisfies it for screen reader users, who can jump by landmark — but a sighted keyboard user has no landmark navigation, and a skip link is their only shortcut past the header. That is why this checker reports a missing skip link, as review, only when there are fifteen or more Tab stops before the main content. A skip link whose target does not exist does nothing, and that is reported whatever the header length.
What is wrong with tabindex="1"?
Any positive tabindex moves the element to the front of the tab order, ahead of everything without one. The search box with tabindex="1" is visited before the logo, the navigation and the skip link, then focus jumps back to the top. It is almost never what was meant. Use tabindex="0" or none, and put the element where it belongs in the source: the DOM order is the tab order.
Can this checker test focus traps and dropdown menus?
No, and it does not pretend to. Whether focus is trapped inside a modal, whether a menu opens on the arrow keys and whether Escape closes it are questions about the running page. This reader sees the HTML before scripts run — what a search engine sees. The free scan renders each page in a real browser before testing it, so it sees the menus, dialogs and widgets JavaScript builds.
It says my page has almost nothing to tab to.
That means the HTML your server sent has fewer than three links, buttons or fields. Almost always the page builds its content in JavaScript after it loads, or the server answered our request with a bot check instead of the page. It is not a finding about your site, and it is not a pass either. Run the free scan, which renders the page in a real browser.
Does this store my domain?
No. The check is a single HTTP GET of the page you name, run inside the request and discarded when it answers. There is no account, no email field and no row written anywhere. If you go on to run the free scan, that one does keep a report so you can come back to it, which is the whole point of a report.

Keep reading