Accessibility
What every Yöte field does without being asked. None of it is opt-in.
Labelling
- A real
<label>wired byhtmlForto a generated id, so clicking the label focuses the field. aria-describedbypoints at whichever of the hint or error is currently showing.aria-invalidwhenever the field is invalid, andaria-requiredwhere the field is required.
Messages
- The message container is an
aria-live="polite"region rather thanrole="alert", which is too noisy on re-render. - It is always in the DOM, even when empty, so an error appearing never moves the form and the live region is a stable node rather than one inserted with its content.
- Error and hint marks are decorative and hidden from assistive tech, because the text carries the meaning.
Input behaviour
- The digit input uses one real field with
inputMode="numeric"andautocomplete="one-time-code", so paste and the SMS suggestion work. - Text is 16px at the control, so iOS does not zoom the viewport when a field takes focus.
- Focus rings are always visible on keyboard focus and never removed.
Dropdowns
Three fields open a list: the country picker inside PhoneInput, SelectInput, and InlineSelect. They share one implementation, so they answer to the same keys and report themselves the same way.
- The control is a
comboboxwitharia-expanded, and the panel is alistboxwhose rows areoptions carryingaria-selected. - The highlighted row is tracked with
aria-activedescendantrather than by moving focus, so the field keeps it and typing never breaks mid-filter. - Arrows move and wrap, Home and End jump, Enter chooses, Escape closes. With the panel shut, Down and Enter open it, which are the two things people try first.
- Pointer and keyboard share one highlight, so hovering and arrowing can never disagree about what Enter will pick.
- The panel renders to
document.bodyand positions against the viewport, so no ancestor's overflow can clip it out of reach.
Tags
- The tags are a real
<ul>of<li>, named bylistLabel, so they are a list to a screen reader rather than chips that happen to sit next to each other. - Adding or removing one is announced in its own polite region, with the new total. The message row cannot carry that, because it is holding the hint.
- Each remove button has a real name from
removeLabel, and it keeps focus in the field so removing three in a row does not mean clicking back in each time. - Backspace on an empty field removes the last tag, guarded on the field being empty so it never eats one while you are still typing.
Masked fields
DateInputandCardInputare ordinary text inputs withinputMode="numeric", not a row of single-character boxes, so selection, paste and a screen reader's own caret review all behave normally.- Punctuation is only ever appended behind a digit, never ahead of the caret, so backspace never has to step over a character you did not type.
- The card mark is decorative and hidden, and its slot is a fixed width, so recognising a card changes no layout and announces nothing.
Motion
- Under
prefers-reduced-motionthe movement goes and the meaning stays: the shake stops, entrances become plain fades, the caret stops blinking. Colour changes are kept, because those are what carry the error. - Hover treatments sit behind
@media (hover: hover) and (pointer: fine), so a tap on a touch device cannot latch a hover state.