Skip to content

Accessibility

LO-TEK promises that accessibility is solved in one place, so each app does not have to solve it again. This page says what the promise covers, and where it ends.

WhatHow
ContrastEvery colour pair is checked against WCAG AA, in both the light and the dark theme
The componentsaxe against WCAG 2.1 level A and AA, in Chromium, Firefox and WebKit
The documentationaxe against every built page, in both themes
The wiring in form fieldsOne implementation, shared by lt.field() and <lt-field>
Target sizeThe site navigation keeps 24 pixels, and that is tested. The other components have no such test yet

The tests run in three browsers because the components build on the browser’s own APIs, and those are exactly what behaves differently.

Windows high contrast replaces the colours on the page with the user’s own set. We have tested what happens in the mode:

SurvivesDisappears
System colours such as Highlight and CanvasTextCustom colours, which are overridden
Borders, and their widthGradients
Masks and data URL imagesbox-shadow

That affects the controls that show their state with colour or a gradient. Without countermeasures, a checked box looks empty, and a switch looks the same in both positions.

ComponentWhat the system does
Checkbox, Radio, Switch, SelectFalls back to the browser’s own rendering, which is correct in every theme the user can pick
Toggle Group, Tag, Pagination, SuggestionShows the selection with Highlight and HighlightText
TabsMarks the selected tab with Highlight on the edge and the text
TooltipGets a border, so the bubble does not float over the content
SpinnerMarks one edge with Highlight, so the ring still has a point
ProgressFills with Highlight inside a border in CanvasText. The indeterminate stripe is drawn in Highlight on Canvas, with forced-color-adjust: none, since a gradient would otherwise disappear
SearchRemoves the icon, which has its colour painted into the image, and gives the space back
Input with a dateRemoves the icon and shows the browser’s own calendar button instead

The switch loses its shape in the mode and becomes a plain checkbox. role="switch" is still there, so it is announced as on and off.

If you write your own CSS, the same applies there: colours you set are overridden. If you need to show that something is selected, use the system colours, which get through:

@media (forced-colors: active) {
.my-selected-row {
background-color: Highlight;
color: HighlightText;
}
}

forced-color-adjust: none exists, but takes away the theme the user has chosen. Use it only when nothing else carries the meaning.

If the user asks for reduced motion in their system settings, the system tones itself down:

ComponentWhat happens
SwitchChanges state without sliding
SpinnerSpins more slowly. It does not stop, because an indicator that stands still no longer says that something is going on.
SkeletonStands still, without shimmer
Skip LinkAppears without sliding
TooltipAppears without a transition
ProgressThe fill does not slide forward, and the indeterminate stripe moves more slowly, for the same reason as the spinner
Select with data-picker="styled"The list opens and the arrow turns, without a transition

Error Summary has no rule of its own. When the user follows a link in the box, Error Summary scrolls to the field without setting the speed itself, so the page’s scroll-behavior decides. If the page has scroll-behavior: smooth, you should turn it off under prefers-reduced-motion: reduce.

A component should never become wider than the space it gets. If it does, the whole page can be dragged sideways, and content ends up beyond the edge.

ComponentWhat happens on a narrow screen
ButtonThe text wraps rather than bursting the box
Pagination, Breadcrumbs, Toggle Group, TabsThe rows wrap onto several lines
TableScrolls sideways in .lt-table-scroll, which you put around it
Dialog, Popover, Toast, Session TimeoutThe width is limited by the screen, not just by a fixed value

Two tests keep this in place. narrow-screen.browser.test.ts puts each component in a 320 pixel box and requires that nothing sticks out. check-mobile.ts opens every page of the documentation at 375 pixels and requires that the page cannot be dragged sideways.

The components use logical properties, such as padding-inline-start and inset-inline-end, and flip by themselves when the document runs from right to left:

<html lang="ar" dir="rtl">

background-position has no logical variant. The four places that draw something in the background, namely the date field, the search field, the select’s arrow and the knob in the switch, are therefore flipped by hand with :dir(rtl). It is tested in all three browsers that the switch knob changes side and so means the same in both directions.

The text content is yours. The system flips the layout, not the language.

The system cannot solve everything centrally. This is up to you:

  • The order of the markup. The keyboard follows the document. If you move something visually with CSS, you do not move focus.
  • Heading levels. lt.heading({ size }) only sets the size. The level has to follow the structure of the page.
  • The text. An error message that says “Invalid value” is technically correct and practically useless.
  • Focus after something happens. If an error, a new panel or a new page appears, focus has to go there. Error Summary does it for forms.
  • Images and icons you add yourself. They need text, or aria-hidden="true" if they are decoration.

axe catches contrast, missing labels and wrong use of aria-*. It does not catch focus handling, order or whether the text makes sense. If you find something that does not work with a keyboard or a screen reader, it is a bug in the system, not something you should work around.