focus:
declarationsince 0.6.0experimentalrequires runtimeMoves focus to the matched element when its value goes from false to true because of a user action. In 0.9 this declaration is the focus request: focus: when(--open).
On this page · 10 sections+−
Syntax
focus: when(<condition>) | var(<boolean state>) | true | false;registry syntax: focus: when(condition) | var(--boolean) | true | false
Parameters
- valuebooleanrequired
- Usually
when(<condition>), which givestrueorfalse. Orfalsein a base rule andtruein a rule for the active item.
Effect
No value. Focus moves once per false → true transition; a value that stays true never refocuses.
Example
.search { --open: state(false);}.search .toggle:on(click) { --open: toggle();}.search .toggle { --attr-aria-expanded: var(--open);}.search .field { display: none;}.search:when(--open) .field { display: block;}/* A focus request: when --open becomes true, the field gets focus. */.search .field { focus: when(--open);}/* From a real focus loss until the next focus. */.search .field:blur { animation: nudge 300ms;}@keyframes nudge { 25% { translate: -4px 0; } 75% { translate: 4px 0; }}state()Function · hover any red tokenMakes each matching element the owner of an independent state with an initial value.Reference →
Resultnative button and search field
waiting for interaction
Correct and incorrect usage
correctFocus the heading of the active step
wizard.cssreactive
/* <h2 tabindex="-1"> in the HTML */.wizard { --step: state(1); }.wizard .panel > h2 { focus: false; }.wizard .panel:nth-var(--step) > h2 { focus: true; }The true declaration moves from one heading to the next as --step changes, and each change is a false → true transition for the new heading. The library never adds tabindex, so the HTML provides it.
incorrectA functional :focus()
dialog.cssreactive
.dialog { --open: state(false); }.dialog input:focus(when(--open)) {}Rejected: :focus is the native pseudo-class and takes no arguments. Write .dialog input { focus: when(--open); }.
Behavior
- 0.9. There is no functional
:focus(…):.field:focus(when(--open)) {}is rejected with a diagnostic, so writefocus: when(--open)in the rule. Native:focus,:focus-visibleand:focus-withinare untouched. - Only state changes made during a trusted
click,keydown,inputorchangearm a transition, and since 0.9 alsopointerupandsubmit, which covers:on(pointerup),:on(submit)and the end of a drag. - Never on page load, insertion, scripts, timers, form reset, focus events, pointer enter/leave or
outside(). - Never overrides focus the user moved since the event, focus already inside the target, or an open
<dialog>or popover that does not contain the target. - Resolved after the state’s CSS and the
--attr-*andcontentwrites; the first eligible target in document order wins. - After the
keydownof Enter or a printable key, focus moves once the key press has finished (next frame), so Enter in a field never also clicks the button that receives focus.
Supported contexts
- Targets must be rendered, not disabled or
inert, and focusable. A non-focusable target is reported; the library never addstabindex. - Trusted stylesheets only.
- In a custom bundle: the
focusfeature, which addsevents.focus: when(…)also needsconditionsforwhen(), which the analyzer adds;focus: var(--open),trueandfalsedo not.
Limitations
- Not verified with screen readers.
- No
focus(selector)action. - Several events before one frame are judged by the final value only.
Examples
- Focus & blur · API examples, runs the real runtime
- Context menu · API examples, runs the real runtime
Related
Experimental · syntax may change between minor versions