Accessibility

Components ship the same accessibility posture as upstream Bootstrap — semantic markup, ARIA where the pattern needs it, keyboard support, and a visible focus ring.

Semantic by default

Components render the right native element rather than a styled <div>. Button is a real <button type="button">; Nav items are links; form controls are real inputs with associated labels. Native elements are focusable and operable with the keyboard before any script runs, and assistive technology announces them correctly.

tsx
// Renders <button type="button"> — focusable and keyboard-operable out of the box.
<Button variant="primary">Save</Button>

// Navigating? Use an anchor so it reads as a link.
<Button as="a" href="/next" variant="link">Next</Button>

ARIA on interactive patterns

The composite components wire the ARIA relationships the WAI-ARIA patterns call for:

  • Modal / Offcanvasrole="dialog", aria-modal, focus trapping, Esc to close, and focus returned to the trigger on close.
  • Dropdownaria-expanded on the toggle, roving focus and arrow-key navigation through items.
  • Alert / Toast — live-region roles so updates are announced.
  • Accordion, Tabs, Pagination, Breadcrumb — the expanded/selected/current state is exposed via aria-expanded, aria-selected, and aria-current.

Keyboard support

Every interactive component is reachable and operable from the keyboard: Tab order follows the DOM, Enter/Space activate controls, Esc dismisses overlays, and arrow keys move within menus, tabs, and carousels. Focus is trapped inside modal surfaces and restored when they close.

Visible focus

Focus indicators use the --bs-focus-ring-* tokens, so keyboard focus is always visible and you can tune it globally through the theme (see the FocusRing helper and the CSS variables page). Do not remove focus outlines — override the ring tokens instead if you need a different look.

Hiding content accessibly

Use the VisuallyHidden helper to provide text for screen readers without showing it visually — for icon-only buttons, skip links, and supplementary labels:

tsx
import { Button, VisuallyHidden, Icon } from '@metatoy/bootstrap-styled';

<Button variant="outline-secondary">
<Icon name="gear" />
<VisuallyHidden>Open settings</VisuallyHidden>
</Button>

Verified against axe

The library’s test suite runs an automated accessibility harness (axe-core) across the component set as part of its Bootstrap-parity checks, so common issues — missing labels, invalid ARIA, insufficient roles — are caught in CI.

Automated checks catch a meaningful slice of accessibility issues but not all of them. Test with a keyboard and a screen reader, and provide accessible names for your own content (alt text, form labels, icon-button labels).