HelixOverviewComponentsMapsGraphIntroductionInstallationDeriving a themeSandboxTheme builderVisual testingCortexDocsEngramBuildingTraceBuildingRecallDeclaredServicesInsightsGet in touchSource on GitHub
Foundations
AccessibilityHelix components handle the structural parts of accessibility, such as roles,
keys, and focus. You handle the parts that depend on your content, such as
names, heading order, and language. A page built from accessible components is
accessible only when you also handle your parts.What the components handleRoles, states, and keyboard interactionEvery component implements the keyboard pattern for its role. You do not write
any of it:Arrow keys move within Tabs, Listbox, Menu, Select, Combobox, and
the days of a date picker.Escape closes an overlay.Home and End go to the first and last item.In Listbox, Select, Menu, and Tree, typing jumps to a matching item.FocusA Dialog traps focus while it is open and returns focus to the element that
opened it. Drawer and the modal mode of Popover do the same.ContrastThe theme engine measures each foreground color against the background it is
actually drawn on. It solves for the contrast target when it computes your
colors. Every pairing is then measured again on a laid-out page. That check
includes the many rules that set only a text color or only a background, so a
pairing nobody planned is still checked. See Surfaces and
separation.Reduced motionFifty-nine stylesheets respond to prefers-reduced-motion individually. Each
component needs its own rule because the base layer's global rule is
*, *::before, *::after in the document, and * does not cross a shadow
boundary. That rule reaches your prose and none of the components. The build
fails when a component animates without responding to prefers-reduced-motion.Disabled controlsdisabled is mirrored to aria-disabled, and the control stays in the
accessibility tree. A screen reader can still announce that the control exists
and is turned off.What you handleNamesEvery control takes label. A component renders the label you give it, and the
words are yours to choose. An icon-only control has no other text to name it:<helix-icon-buttonlabel="Close"name="x"></helix-icon-button>A button, a form control, a button group or an open dialog that has no name
warns once in the console: <helix-icon-button> has no accessible name,
followed by the ways to give it one. The check runs a moment after the control
first renders, so a label your framework writes beside the control in the same
pass counts. The warning has the
kind missing-name, so @fusion.dev/helix-diagnostics counts it with the
other runtime events.The warning prints in development builds only. Vite and webpack ask for the
development export condition while you develop, and so do
bun --conditions development and node --conditions=development. A production
build resolves the check to a function that does nothing and carries none of
its code.label and aria-labellabel renders visible text and names the control through that text.
aria-label names the control and shows nothing on screen. Use aria-label
only when the page already makes the control's purpose plain. That case is less
common than it seems.Heading orderComponents render the heading levels you give them. A Card does not add an
h2 for you, because the right level depends on the headings above the card.Language and directionSet lang and dir on the document. Components use logical properties
throughout, so a right-to-left document lays out correctly. Helix does not
detect the direction for you. See Localization and RTL.Live regions for your own updatesComponents announce their own state changes. To announce a message from your
application, put it in an Announcement:<helix-announcementtone="warning">Your trial ends on Friday.</helix-announcement>Announcement is always a polite live region. An assertive region, such as
role="alert", interrupts whatever the screen reader is reading. That suits a
message that appears during a session. It does not suit a message in the served
HTML, because an assertive announcement would interrupt a screen-reader user on
every page load, before they had read anything. A polite announcement can arrive
a moment later, and it is always safe to use.Callout is a different component. It is a passage that interrupts a document
and is read where it sits. Neither component is a variant of the other.Two things the shadow boundary changesaria-labelledby and aria-describedby inside a shadow root cannot point to an
id in your document. The browser drops the reference silently and reports no
error. For this reason, every control renders its own label. See
Forms and validation.What you write on the host reaches the control inside it. The form controls,
Button, and IconButton carry these down to the element a screen reader is on:aria-labelledby and aria-describedby, as element references, so the ids
you name in your document resolve.A <label for> that points at the host, or a <label> around it, when the
control has no label of its own.aria-expanded, aria-haspopup, aria-controls, aria-invalid, and
aria-pressed.aria-label on Button, IconButton, and Switch. A field renders its
aria-label as a hidden label.A <label> around a control also reads the words inside the control, such as
the names of its buttons. Use <label for> or the control's own label to name
it with your words alone.When a relationship has to cross the boundary, the components use
ElementInternals and element-reference properties. They are the only mechanism
that works across the boundary. Use the same tools when your own components need
such a relationship.Hide text visuallyTo hide text on screen and keep it for screen readers, add
data-hidden-visually:<spandata-hidden-visually>Sorting by</span>The base layer's [data-hidden-visually] rule clips the element.
display: none and visibility: hidden both remove the element from the
accessibility tree, so they hide the text from screen readers too.What we do not testWe test Helix in Chromium with automated specs and pixel baselines. We do not
run it through a screen reader on every release. The component patterns follow
the ARIA authoring practices, and they have not been certified against them. If
you find a real failure, report it as a bug.