# Focus

> Real focus on real controls: where it lands, how it is shown, and where it goes when what held it opens, closes or goes.

Focus is where the keyboard's keys go. Someone using a keyboard, a switch or a
screen reader works through focus alone: they need to see where it is, to know
where it will go, and never to find it gone. An interface that handles focus
well puts it on real controls, shows it where it was brought by the keyboard,
and moves it only where the person would expect.

## Best practices

**Give focus to real controls.** What takes keys holds the browser's own focus,
on the browser's own control wherever there is one: the active cell of a grid
holds a text field, a checkbox or a button, and an item of a list is a real
element with focus. Typing, an input method's composition, the clipboard, spell
checking and assistive technology then work as the platform makes them work,
rather than as a reconstruction of it.

**Move focus itself through a composite, rather than pointing at an item.** A
list, a grid or a canvas is one stop in the Tab order. Within it the arrow keys
move the browser's focus from item to item, and the item that last had it keeps
the one Tab stop (a "roving" tab stop). The alternative — focus staying on the
container while it names an active item for assistive technology — leaves the
item without the focus its own control needs, and leaves the browser's own
scrolling, focus styles and text input unaware of where the person is. This
library uses it nowhere.

**Enter where the person was.** Tabbing into a composite lands on the item last
focused, else on the first selected, else on the first. Tab again leaves it.

**Show focus the keyboard brought.** A ring is drawn around what has focus when
the keyboard brought it there, and not after a press, where the pointer already
says where it is. It is an outline two pixels wide in the focus colour, a
little apart from the control's edge, or within it where the control sits
flush against its neighbours or inside a region that clips.

**Draw it so a forced palette keeps it.** Where the system forces its own
colours, a ring drawn as a shadow disappears; an outline is kept and takes the
system's colour. The same holds for showing that a value is not allowed: a
heavier edge, which does not rest on colour alone.

**Move focus into what opens, and back when it closes.** An overlay takes focus
to its first control when it opens, or to itself when it has none. When it
closes, focus returns to the control that opened it — unless the person has
moved it elsewhere — or, with no such control, to what had it before.

**When what has focus goes, give it to what is beside it.** A removed item hands
focus to the next, else the one before, else to the control that adds another;
a removed last connection hands it to the nodes. Focus is never left on
something that is no longer in the page.

**Never lose focus to the page.** Focus that falls to the document's body is
lost: the next Tab starts again from the top, and a screen reader announces
nothing useful. Whatever removes, closes or replaces what had focus says where
focus goes instead. Something that is pressed outlives the press, since a
browser may drop focus to the page if what was pressed is removed before the
press ends.

**Do not move focus to say something.** What happened elsewhere is announced
where the person is (see [Announcements](https://ui.publictheta.com/foundations/announcements.md)); focus
stays on their work.

**Do not take focus that was not asked for.** An item focused by the
application is brought into view; an item pressed by the pointer is not moved
from under it by being focused.

## Where each rule is verified

| Rule                               | Clauses                                                                                                                                                                                                                                                                    |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| One Tab stop, entered where it was | [Listbox](https://ui.publictheta.com/components/listbox.md): “Tab enters on the first selected option”, “returning to the list returns to the option last focused”; [Data grid](https://ui.publictheta.com/components/data-grid.md): “the grid is one stop in the Tab sequence: Tab enters at the active cell, and Tab again leaves” |
| Reading order through a plane      | [Canvas](https://ui.publictheta.com/components/canvas.md): “Tab into the canvas lands on one item: the first in reading order, wherever it is among the items”                                                                                                                                          |
| Into an overlay and back           | [Overlays](https://ui.publictheta.com/foundations/overlay.md): “opening moves focus to the first thing inside that takes it”, “closing returns focus to the control that opened it”, “focus returns to the control when the content is removed in the act of closing”                                   |
| With nothing to return to          | [Overlays](https://ui.publictheta.com/foundations/overlay.md): “with no control to return to, closing returns focus to what had it before”                                                                                                                                                              |
| What had focus goes                | [Listbox](https://ui.publictheta.com/components/listbox.md): “when the option that has focus goes away, focus stays in the list”; [Canvas](https://ui.publictheta.com/components/canvas.md): “when the item that has focus is taken away, focus stays in the canvas”                                                                 |
| Removing hands focus on            | [Object editor](https://ui.publictheta.com/components/object-editor.md): “removing an item moves focus to the next item, else the one before, else the button that adds one”; [Diagram](https://ui.publictheta.com/components/diagram.md): “when the last connection is removed, focus goes to the nodes”                            |
| The ring                           | this page's spec: “focus the keyboard brought is drawn”, “focus a press brought is not drawn”, “where the system forces its own colours, the ring is still drawn”                                                                                                          |

## Platform considerations

**Keyboard on a Mac.** Safari leaves buttons out of the Tab order unless the
person has asked for every control; a composite that must be reachable is
reachable through its own items, not only through buttons.

**Touch.** A tap does not show a focus ring. A field given focus on a phone
brings up the on-screen keyboard, so focus is moved into a field on a phone only
when the person asked to type — a day chosen from a date field's calendar on a
phone does not put focus back in the field, which would raise the keyboard over
the date just chosen.

**Assistive technology.** A screen reader reads what takes focus: its name, its
role, its state and its place among its siblings. That is the best announcement
there is, and is not repeated by a live region.

## Behaviour

Each statement is verified by a test in Chromium, Chromium (touch), Firefox, WebKit, WebKit (touch), unless it names the environments it applies to or is marked open.

### The ring

- Focus the keyboard brought is drawn: an outline two pixels wide in the focus colour, a little apart from the edge.
- Focus a press brought is not drawn: the press already says where it is.
- Where the system forces its own colours, the ring is still drawn, in the system's colour.
- For what sits flush against its neighbours, the ring is drawn within its edge.
- For a field, the ring is drawn over its own border, which it thickens.

### What is not allowed

- A control holding what is not allowed has a heavier edge in the danger colour, not a colour alone.

## Reference implementation

React: `npx shadcn@latest add https://ui.publictheta.com/r/focus.json`
