PLAINFINCH learn by building

Using a page with a keyboard

You will move through a page using only the keyboard, and turn a control that cannot get focus into a real button.

Who uses a website without a mouse?

More people than you might guess. Blind people use the keyboard, because a mouse needs you to see the pointer. People with tremors, arthritis or repetitive strain often find keys easier than aiming at small targets. Some people use a switch, a single large button pressed with a hand, foot or head, which the computer turns into Tab and Enter. Voice control software and many on-screen keyboards also send key presses behind the scenes.

Plenty of people who could use a mouse prefer not to. Developers, writers and anyone filling in a long form move faster with Tab. A laptop with a broken trackpad turns any of us into a keyboard user for a week.

All of these people depend on one rule from WCAG, 2.1.1 Keyboard: everything you can do with a mouse must be possible with a keyboard alone, without needing exact timing. It is level A, the most basic level, because when it fails, a whole group of people is stuck.

Which keys do keyboard users press?

A small set covers most of the web. Learn these and you can test any page in a few minutes.

Screen reader users have many more keys, such as H to jump to the next heading, but those come from the screen reader. Your job as a builder is to make sure the browser keys above work everywhere.

  • Tab moves focus to the next link, button or form field. Shift+Tab moves back.
  • Enter follows a link or presses a button. In a single-line text field inside a form, it usually submits the form.
  • Space presses a button, ticks a checkbox and scrolls the page when focus is on plain content.
  • Arrow keys move between radio buttons in a group, choose options in a <select>, move the cursor in text and scroll the page.
  • Escape closes a dialog, a pop-up or a menu, and cancels many browser actions.

What has to be reachable with Tab?

Everything a visitor can act on: links, buttons, form fields, and any custom control like a tab panel or a slider. Each of these should be a Tab stop, in an order that matches the page, and each should do its job with the expected key.

Plain content stays out of the Tab order. Headings, paragraphs and images are read by screen readers using their own reading keys, and keyboard users who can see scroll with the arrow keys and Space. Adding tabindex="0" to paragraphs makes Tab slower for everyone and makes nothing more accessible. The Tab order lesson covers tabindex in detail.

Look at the starting page in the **Keyboard** view. It lists Shop and Repairs, then stops. The Add to basket control, the reason the page exists, is missing. A keyboard user can read about the repair kit and cannot buy it.

Why does a div with onclick fail keyboard users?

A <div> is a generic box. The browser does not put it in the Tab order, does not give it a role, and does not connect any key to its onclick. The onclick attribute fires for mouse clicks and taps. On a <div>, nothing makes a key press count as a click.

You could patch it: add tabindex="0" to make it focusable, role="button" so screen readers call it a button, and a keydown handler that runs the same function for Enter and Space. That is three changes, and each is easy to get slightly wrong. Real buttons also activate on Space when the key comes up, ignore the press if you move away, and handle being disabled. A hand-built copy rarely matches all of it.

Change the element instead. A <button> gets focus, the button role, Enter and Space activation and the disabled state from the browser, for free. Its onclick already fires for keyboard presses, because the browser turns Enter and Space on a button into a click event. This is the reason to prefer native HTML: the behaviour is already written and tested.

<!-- Tab skips it, Enter does nothing -->
<div class="add" onclick="addToBasket()">Add to basket</div>

<!-- Tab reaches it, Enter and Space press it -->
<button type="button" class="add" onclick="addToBasket()">Add to basket</button>
FigureA div with onclick saying Add to basket is skipped by Tab, ignores Enter and Space, and has no role. A button with the same onclick is reached by Tab, pressed by Enter and Space, and has the button role.A div with onclick saying Add to basket is skipped by Tab, ignores Enter and Space, and has no role. A button with the same onclick is reached by Tab, pressed by Enter and Space, and has the button role.
Same text, same onclick. Only the button gets a Tab stop, Enter and Space, and a role, all from the browser for free.

What else do native controls give you for free?

Links with an href are focusable and follow on Enter. Remove the href and the browser treats the <a> as a placeholder: no focus, no link role, no Enter. AI tools sometimes write <a onclick="..."> with no href, which looks right and fails exactly like the <div> did.

Form fields bring a lot. A <select> opens with the keyboard and changes with the arrow keys. A group of radio buttons with the same name is a single Tab stop, and the arrow keys move between options. A <details> element opens and closes its <summary> with Enter and Space. A <dialog> opened with showModal() closes on Escape.

The type="button" on the new button is there for a different reason. Inside a <form>, a button with no type is a submit button. Pressing it would submit the form. Writing the type out says what the button is for and avoids surprises if the markup later moves into a form.

How do you test a page with the keyboard?

Put the mouse out of reach. Click in the browser's address bar, then press Tab and watch where focus lands. Keep pressing until you have been through the whole page, and Shift+Tab back to the start. On every stop, ask three questions: can I see where I am, is this the order I expect, and does Enter or Space do what a click would do.

The **Keyboard** view here does the same thing in a list. It shows every Tab stop with its role and name, and buttons to press Tab, Shift+Tab, Enter, Space and Escape on the live page. Press Show numbers to label the stops on the page itself, which makes gaps easy to spot.

On a Mac, Safari skips links when you press Tab unless you turn on “Press Tab to highlight each item” in its settings, and macOS may need keyboard navigation switched on in System Settings. If Tab seems to skip every link while testing on a Mac, check those settings first.

Does a keyboard fix help screen reader users too?

Yes, in most cases. Screen readers lean on the same roles and focus the browser provides. After the fix, the **Screen reader** view says button, Add to basket where it used to read the words as plain text. A screen reader user now knows the words are something to press, and the screen reader's own shortcut for jumping between buttons can find it.

The basket line is a role="status" live region, which the Announcing changes lesson covers. Each time the count changes, a screen reader reads it out without moving focus. Press Space on the button in the Keyboard view and the announcement appears in the Screen reader view.

What do AI tools get wrong about keyboard access?

Clickable <div> and <span> elements are one of the most common problems in generated code, especially in component libraries and quick prototypes. Look for onclick on anything that is not a <button> or an <a href>, and for cursor: pointer on generic elements, which hints that something was meant to be clickable.

Also watch for links with no href, menus that only open on hover, and custom dropdowns built from <div> elements that ignore the arrow keys. When you find one, the first question is always whether a native element would do the job. It nearly always would.

Field notes

  • Many people use the keyboard instead of a mouse.
  • Tab moves to the next link, button or field, and Shift+Tab goes back.
  • Everything you can act on must be reachable with Tab.
  • A real <button> works with Enter and Space without extra code.

Easy to get wrong

A <div> is never a Tab stop and ignores Enter and Space. A <button> is focusable and turns those keys into a click, with no extra code.

An <a> without href isn't a link to the browser. It loses focus, the link role and Enter. It also breaks middle-click, copy link and open in new tab.

Only things people act on belong in the Tab order. Screen reader users read paragraphs with reading keys, so a focusable paragraph adds a stop and helps nobody.

Questions people ask

Can I keep the div and add keyboard support with JavaScript?

You can, with tabindex="0", role="button" and a keydown handler for Enter and Space. It is more code and it is easy to miss details, such as Space firing on key up. Use a <button> unless there is a real reason not to, and there rarely is.

Why does Space scroll the page instead of pressing my control?

Because focus is not on a button. Space presses a focused button, and on any other content it scrolls. If Space scrolls when you expect it to press something, the control is probably not a real button or it never got focus.

Do I need to support every keyboard shortcut a screen reader uses?

No. Screen readers bring their own keys and read the structure your HTML provides. Your part is real elements, sensible headings and landmarks, and controls that work with Tab, Enter, Space, the arrow keys and Escape.

Is a link or a button right for Add to basket?

A button. It changes something on the current page and does not go to a new address. Links go places and buttons do things; the Buttons and links lesson covers the choice.

Keep going