Accessibility is built into every component instead of being left to the app. Components render the right elements, roles and states, support the keyboard and announce changes on their own. What only your app knows, such as the name of a control without a visible label, goes through a small set of props.
Components render real HTML elements: a button is a button, a text field an input, a navigation a nav and a dialog a dialog. ARIA roles are added only where no native element fits, such as a combobox, a listbox or a tab list. They follow the WAI-ARIA authoring patterns.
Every text meant only for screen readers goes through one ariaLabels prop. Its keys name the component itself after its element, such as trigger, input, group or nav. Other keys name its inner parts, such as a clear or a close button.
Texts that need one come with English defaults, translated as described on the Localization page.
A form control placed in a Field takes its name from the visible Field label, which screen readers announce together with the hint and the error.
<Select ariaLabels={{ trigger: 'Country' }} items={countries} /> <Field label="Country"> {({ attrs }) => <Select elemAttrs={attrs} items={countries} />}</Field>During development a control left without any name logs a console warning that names the component and the ariaLabels key to pass. A Field label or an aria-label counts as a name. Production builds leave these warnings out.
[NebulaKit]: Select has no accessible name, pass ariaLabels.trigger or wrap it in a Field with a labelInteractive components support the keys their WAI-ARIA pattern expects, such as arrow keys in lists, tabs and radio groups or typing to jump to an option.
Every focusable element shows a visible focus ring when it is reached with the keyboard.
Dialogs keep the focus inside while open and return it to the element that opened them. Escape closes only the topmost layer, so a list open inside a dialog closes first.
A loading button keeps the focus, so keyboard users do not lose their place.
States such as selected, expanded, checked, invalid or disabled are exposed to assistive technology, not only drawn on screen.
Field announces an error as soon as it appears and marks a required control.
Snackbar messages are read out as they appear, errors more urgently than the rest.
Content that only decorates is hidden from screen readers, content that carries meaning gets a name. Icons are decorative unless they are named through ariaLabels. Image requires alt text where an empty one marks a decorative image. Avatar is named by its alt. A HorizontalRule set to decorative is hidden as well.
When the system asks for reduced motion, decorative animations such as the ripple are left out.