Accessibility
Foundations

Accessibility

Keyboard navigation, focus management, accessible labels, motion preferences, and contrast checks.

Onset provides focus indicators, keyboard handlers, and accessibility attributes for its components. Application code supplies labels, content, and focus behavior for custom compositions. Component references document individual keyboard patterns and limitations.

Keyboard & focus

Native buttons and inputs use browser keyboard behavior. Components such as Tabs, Carousel, and SplitPane add the keyboard interactions documented on their reference pages. TreeView and MiniCalendar use Tab navigation without arrow-key navigation.

Focus rings

Focus styles use --m-focus-outline, --m-focus-offset, and --m-focus-ring CSS variables.

  • --m-focus-outline draws outside the border. Ancestors with overflow: hidden can clip the outline.
  • --m-focus-ring and --m-focus-ring-inset use box shadows within the element's bounds. These styles are used in clipped or scrolling regions.

Focus trapping

Modal and Drawer use Dialog to trap focus while open. Popover provides positioning without a focus trap.

useFocusTrap moves initial focus into a container, wraps Tab navigation at its boundaries, and attempts to restore the previously focused element on cleanup. initialFocusRef selects the initial target. Set autoFocus or restoreFocus to false to disable the corresponding behavior.

Scroll locking

useScrollLock sets overflow: hidden on document.body while enabled and restores scrolling on cleanup. Dialog includes scroll locking.

Scrolling regions

ScrollArea adds its viewport to the tab order while content overflows. Carousel handles arrow keys, Home, and End on its track.

Resizable panes

Each SplitPane divider has role="separator" and reports the leading panel's share through aria-valuenow. Arrow keys resize by step percentage points. Home and End select the size limits. Enter toggles a collapsible panel.

Dismissal

useDismiss calls onDismiss for Escape and pointer presses outside the elements listed in ignoreRefs.

Custom overlayTSX
import { useRef } from "react";
import { useDismiss, useFocusTrap } from "@solarius/onset";

function CustomOverlay({
  open,
  onClose,
}: {
  open: boolean;
  onClose: () => void;
}) {
  const panelRef = useRef<HTMLDivElement>(null);
  useDismiss({ enabled: open, ignoreRefs: [panelRef], onDismiss: onClose });
  useFocusTrap({ enabled: open, containerRef: panelRef });

  return open ? (
    <div ref={panelRef} role="dialog" aria-modal="true" aria-label="Details">
      <button onClick={onClose}>Close</button>
    </div>
  ) : null;
}

Include a trigger ref in ignoreRefs when trigger presses should not dismiss an open overlay.

Screen readers

VisuallyHidden

VisuallyHidden hides text visually while retaining the text in the accessibility tree. Use the component to label controls that have no visible text.

Accessible labelTSX
import { VisuallyHidden } from "@solarius/onset";

<button type="button">
  <VisuallyHidden>Close dialog</VisuallyHidden>
  <span aria-hidden="true">×</span>
</button>;

Icons

Icon forwards SVG attributes to the supplied icon component. Set aria-hidden="true" on decorative icons. Label icon-only buttons with aria-label or visually hidden text.

Form validation

Field passes its error state to nested controls for invalid styling. ValidationMessage renders role="alert" for errors and role="status" for other tones. Associate descriptions with inputs through matching id and aria-describedby attributes in custom layouts.

Color contrast

Theme configuration changes generated foreground and background colors. Verify the color pairs used by the application after changing baseColor, status colors, or surface styles. WCAG AA requires a contrast ratio of 4.5:1 for normal text and 3:1 for large text.

Status colors use per-mode values unless overridden through theme configuration. Do not rely on color alone to communicate status. Include a label or another visible indicator.

Accessibility support

Custom compositions require application-level checks:

  • Label controls and associate field descriptions and errors.
  • Check keyboard navigation and focus restoration after closing overlays or removing content.
  • Verify contrast for the actual foreground and background pairs.
  • Keep required actions available without hover or pointer dragging.

Motion preferences

Skeleton disables animation under prefers-reduced-motion. Carousel stops automatic advancement and smooth scrolling. Spinner uses an opacity pulse instead of rotation. Use useReducedMotion for custom animations.