Focus Management
Deliberately moving focus when the interface changes, so keyboard and screen reader users are not stranded.
Definition
Focus management is the practice of directing keyboard focus in response to interface changes: opening dialogs, navigating in a single-page application, revealing content and handling errors.
Craft convention. True because the industry converged on it. Breaking it costs familiarity, not correctness.
On this plate
Reach for this when
- Building dialogs, drawers or any overlay.
- Single-page application routing.
- Form error handling.
Common mistakes
- Focus lost on route change.
- Focus left on a removed element.
- Focus stolen while the user is typing.
- Focus traps with no escape.
Where focus should go
| Event | Focus destination |
|---|---|
| Dialog opens | The dialog, usually its heading or first control. Trap focus inside. |
| Dialog closes | Back to the element that opened it. |
| Route change in a single-page app | The main heading of the new view, or a dedicated announcer region. |
| Form submitted with errors | The error summary, or the first invalid field. |
| Content expanded in place | Usually stays on the trigger, with aria-expanded updated. |
| Item deleted from a list | The next item, or the list container if it is now empty. |
Rules
- Move focus only in response to a user action, never spontaneously.
- Do not move focus while someone is typing.
- Trap focus only in modal contexts, and always provide Escape.
- When focusing a non-interactive element such as a heading, give it tabindex -1 rather than making it tabbable.
- Never leave focus on an element that has been removed from the DOM.
The two cases that are always wrong by default
// 1. Dialog: remember the trigger, restore on close
let previouslyFocused = null;
function openDialog(dialog) {
previouslyFocused = document.activeElement;
dialog.showModal(); // native dialog traps focus for you
dialog.querySelector("h2").focus(); // heading carries tabindex="-1"
}
function closeDialog(dialog) {
dialog.close();
previouslyFocused?.focus(); // never leave focus on a removed node
}
// 2. Client-side route change: nothing is announced unless you do it
function onRouteChange(view) {
const heading = view.querySelector("h1"); // tabindex="-1"
heading.focus();
announce(`${heading.textContent} loaded`); // writes into a live region
}A dialog that returns focus to its trigger, and a route change that both moves focus and announces the new view. Neither happens on its own.
Moving focus without disorienting people
Do
- Move focus to the thing the reader asked for, and to the top of it rather than into the middle.
- Return focus to the trigger when a layer closes, even if the trigger has moved.
- Focus the error summary on a failed submit, so the first thing announced is what went wrong.
- Check what happens when the focused element is deleted, which is the case nobody tests.
Do not
- Do not move focus on page load, on a timer, or on anything the reader did not initiate.
- Do not focus a field while someone is typing in another one.
- Do not trap focus in a non-modal layer such as a dropdown or a toast.
- Do not scroll an element into view without focusing it, which moves the sighted reader and nobody else.
Focus has to come back
Commonly confused with
Close neighbours that get substituted for each other. The difference is stated first, then the condition that picks one over the other.
Focus Indicators
AccessibilityWhether the focused element is clearly indicated, and under which input methods.
Key difference
Focus visibility is whether you can see where focus is. Focus management is where focus goes when the interface changes underneath it. A page can pass one and fail the other completely.
Use Focus Management when
- A dialog, drawer or route change has just happened.
- Focus jumped to the top of the page, or vanished entirely.
- The question is order and destination, not appearance.
Use Focus Indicators when
- Someone tabs through and cannot tell where they are.
- A ring has been removed, or is too faint against its background.
- The question is styling and contrast of the indicator.
Local chart
A11Y·004 · Region V · Grid B4
This entry and the entries it is stated to connect with. Each line is labelled with what the connection means.
Continue from here
Each link says what the connection is, so you can tell a principle from an alternative from a thing people mix this up with.
Applies when you are designing
Relied on by
Entries that assume this is already in place.
- Drawer and SheetCMP·011 · Component
- Modal DialogCMP·010 · Component
- PopoverCMP·012 · Component
- Input ValidationPAT·007 · Pattern
Short definition
The one-paragraph version, for when that is all you need.
- Focus OrderTERM·077 · Term
- Focus TrapTERM·078 · Term
- ModalTERM·048 · Term
Related concept
Connected closely enough to change how you apply this.
- Keyboard NavigationA11Y·002 · Accessibility
- Screen ReadersA11Y·005 · Accessibility
- Status Messages and Live RegionsA11Y·009 · Accessibility
- ElevationFND·048 · UI foundation
- Figure and GroundFND·009 · UI foundation