accessibility
Focus delegation
also called delegatesFocus (whatwg-html), dead focus zone (community), host focus forwarding (community)
A shadow root option that forwards focus from the host into the first focusable element inside it, so clicking the padding of a custom element does not leave focus nowhere.
attachShadow({ mode: 'open', delegatesFocus: true }) makes a custom element pass focus through
itself. A click on any part of the host that is not focusable in its own right moves focus to the
first focusable element inside the shadow tree, calling host.focus() does the same, and the host
matches :focus and :focus-visible while the inner element holds it, so the ring can be drawn
around the component rather than around the input buried in it.
Without it you get a dead focus zone, and it is a bug people meet before they have a word for it. A component with comfortable padding is mostly host: a reader clicks half a centimetre from the input, the press lands on the host, the host is not focusable, and focus goes nowhere. Typing does nothing. Worse, focus is now on the body, so the next Tab starts again from the top of the document rather than from where the reader was, which quietly wrecks focus order for anyone who mixes pointer and keyboard. Nothing on screen says any of this happened, which is why the same component ships broken twice.
The forwarding is literal: it goes to the first focusable element in tree order, not to the one you
consider the main control, so a Clear button rendered before the input will win. It is decided once,
when attachShadow runs, and cannot be flipped later. It changes what a press inside the component
means, so it can fight text selection: dragging across static text in the shadow tree is a press in
a non-focusable area, and a press in a non-focusable area is now a focus move. And it is not a fix
for what is or is not tabbable inside your component, nor a substitute for deciding
initial focus when a component opens. It solves exactly one thing, which is that
the host should not be able to eat a click.
This site is a good place to notice it, because every inline specimen on it is exactly such a host:
<vd-stage> puts each demo in a shadow root, and everything a reader clicks in one is inside that
tree. Any custom element with generous padding, a card, a field wrapper, a media control, a stage,
should ask whether a press on its own body ought to reach the control inside it. Usually the answer
is yes, and the option is one line.
Which word?
| If you want | say |
|---|---|
| a custom element swallows clicks near its edges | focus delegation |
| a dialog opens and nobody decided where focus goes | initial focus |
Related
See also: Hit slop