The application draws every one of its own surfaces, and then six controls come from the operating system and bring its chrome with them — a different border, a different radius, a different arrow, a different focus ring, and on Windows a different font:
| control |
where |
<select> Langue, Thème, Densité |
the preferences panel |
<select> language |
the editor's toolbar |
<input type="date"> |
the editor's meta row, beside the lifecycle badge |
<select> "Déplacer vers" |
the selection bar |
<select> "Ranger dans" |
the selection bar |
The last two are worse than a mismatch: they are a <select> doing a command's job. The value is reset to '' after every change, so it is a menu pretending to be a field — a screen reader announces a combobox whose current value is "Ranger dans", and a keyboard user gets a listbox where the rest of the application gives a menu.
The pieces to build them with already exist: appMenuTrigger / appMenuPanel / appMenuItem own the roving focus, the Escape and the outside click, and note-card-menu is the worked example.
Shape
- The two selection-bar selects become menus on the existing directives. They are commands, so
role="menu" is the correct role and the reset hack disappears with the element.
- The three preference selects and the editor's language select become the same menu, or a segmented control where there are three options (Thème, Densité) — three radio-like choices read better than a dropdown.
- ⚠️ The date input is the hard one. A native
<input type="date"> brings a free calendar, localisation and keyboard entry that a hand-rolled picker has to earn back. Options, in order of cost: style what can be styled (::-webkit-calendar-picker-indicator, the field's own box) and accept the popup; or keep the input and put it behind a control that matches, opening the picker with showPicker(). Do not hand-roll a calendar for this ticket.
- ⚠️
color-scheme is already set on :root for exactly this reason — it is what keeps the native popup dark. Whatever replaces a select must not take that away from what is left.
Done when
Nothing in the window carries the operating system's chrome except the date picker's popup, and the two selection-bar commands are menus rather than fields.
The application draws every one of its own surfaces, and then six controls come from the operating system and bring its chrome with them — a different border, a different radius, a different arrow, a different focus ring, and on Windows a different font:
<select>Langue, Thème, Densité<select>language<input type="date"><select>"Déplacer vers"<select>"Ranger dans"The last two are worse than a mismatch: they are a
<select>doing a command's job. The value is reset to''after everychange, so it is a menu pretending to be a field — a screen reader announces a combobox whose current value is "Ranger dans", and a keyboard user gets a listbox where the rest of the application gives a menu.The pieces to build them with already exist:
appMenuTrigger/appMenuPanel/appMenuItemown the roving focus, the Escape and the outside click, andnote-card-menuis the worked example.Shape
role="menu"is the correct role and the reset hack disappears with the element.<input type="date">brings a free calendar, localisation and keyboard entry that a hand-rolled picker has to earn back. Options, in order of cost: style what can be styled (::-webkit-calendar-picker-indicator, the field's own box) and accept the popup; or keep the input and put it behind a control that matches, opening the picker withshowPicker(). Do not hand-roll a calendar for this ticket.color-schemeis already set on:rootfor exactly this reason — it is what keeps the native popup dark. Whatever replaces a select must not take that away from what is left.Done when
Nothing in the window carries the operating system's chrome except the date picker's popup, and the two selection-bar commands are menus rather than fields.