Skip to content

Accessibility

Refine targets WCAG 2.1 AA compliance across the component library. ARIA roles and states are managed automatically. Keyboard navigation, focus management, and live-region announcements are built into each component.

What You're Responsible For

Most accessibility is handled for you. Two things require action on your side:

  • Icon-only buttons must have a label attribute — it becomes aria-label. Without it, screen readers have nothing to announce.
  • Decorative icons should have aria-hidden="true" so screen readers skip them. Meaningful standalone icons need an aria-label.
html
<!-- Icon-only button — label required -->
<ore-button icon-only label="Delete item" color="error">
  <ore-icon name="trash-2" size="18"></ore-icon>
</ore-button>

<!-- Decorative icon — hidden from screen readers -->
<ore-icon name="check" size="16" aria-hidden="true"></ore-icon>

<!-- Meaningful standalone icon -->
<ore-icon name="warning" size="16" aria-label="Warning"></ore-icon>

You can also connect an input to external help text using aria-describedby:

html
<ore-input label="Password" aria-describedby="pwd-hint" />
<p id="pwd-hint">Minimum 8 characters, one uppercase, one number.</p>

Testing Strategy

Refine uses a three-layer approach.

1 — Unit tests (jsdom + Ore test helpers)

Every component has tests verifying correct role and aria-* attributes at render time, ARIA state changes on attribute mutation, keyboard event handling, focus management for overlays, and live-region announcements.

2 — Axe-core automated audit

The axeCheck helper is available globally in all Refine tests:

ts
import { mount } from '@vielzeug/ore/testing';

it('has no axe violations', async () => {
  const fixture = await mount('ore-button', { attrs: { color: 'primary' } });
  const results = await axeCheck(fixture.element);
  expect(results.violations).toHaveLength(0);
});

Only the wcag2a, wcag2aa, and best-practice rule sets run in CI to keep test suites fast.

3 — Manual checklist (per release)

Before each minor release:

  • [ ] Focus order is logical and follows visual layout
  • [ ] All interactive controls have visible focus rings
  • [ ] No unintentional keyboard traps (dialogs and drawers are intentional)
  • [ ] Dynamic changes (toasts, alerts, async states) are announced
  • [ ] Images and icons have appropriate alt or aria-hidden
  • [ ] Form labels are connected to their controls
  • [ ] Error states are communicated in text, not color alone

Per-Component Coverage

Inputs

ComponentRoleKeyboardKey ARIA attrs
ore-buttonbutton (implicit)Enter / Spacearia-disabled, aria-busy
ore-inputtextbox (native)Standardaria-describedby, aria-invalid, aria-required
ore-textareatextbox (native)Standardaria-describedby, aria-invalid, aria-required
ore-selectcomboboxArrow / Enter / Escapearia-expanded, aria-activedescendant
ore-comboboxcomboboxArrow / Enter / Escapearia-expanded, aria-activedescendant
ore-checkboxcheckbox (native)Spacearia-checked, aria-required
ore-radioradio (native)Arrow keys (group nav)aria-checked
ore-switchswitchSpacearia-checked
ore-slidersliderArrow keysaria-valuenow, aria-valuemin, aria-valuemax, aria-valuetext
ore-ratingradiogroup + radioArrow keysaria-label per star
ore-number-inputspinbuttonArrow keysaria-valuenow, aria-valuemin, aria-valuemax
ore-otp-inputgroup of text inputsArrow / Backspace / Tabaria-label per cell
ore-file-inputbutton-triggered nativeStandardaria-label

Feedback

ComponentRoleKeyboardKey ARIA attrs
ore-alertalert / statusDismiss buttonaria-live via region
ore-toastalert / statusDismiss buttonaria-live="polite" or "assertive"
ore-asyncDynamicaria-busy, aria-live, role="alert" in error
ore-progressprogressbararia-valuenow, aria-valuemin, aria-valuemax, aria-valuetext
ore-skeletonNone (decorative)aria-hidden="true" on bones
ore-badgeNonearia-label if meaningful
ore-chipbutton (interactive)Enteraria-pressed, aria-label

Disclosure

ComponentRoleKeyboardKey ARIA attrs
ore-accordionbutton + regionEnter / Spacearia-expanded, aria-controls
ore-tabstablist + tab + tabpanelArrow keysaria-selected, aria-controls, aria-labelledby

Overlay

ComponentRoleKeyboardKey ARIA attrsNotes
ore-dialogdialogEscape, focus traparia-modal, aria-labelledbyFocus restored on close
ore-drawerdialogEscape, focus traparia-modal, aria-labelledbyFocus restored on close
ore-popoverdialog / menuEscapearia-expanded, aria-haspopup
ore-menumenu + menuitemArrow / Enter / Escapearia-orientation
ore-tooltiptooltipEscapearia-describedby on trigger

Content

ComponentRoleKeyboardKey ARIA attrs
ore-cardbutton (interactive)Enter / Spacearia-disabled, aria-busy
ore-tabletable (native)Standardaria-label, aria-busy
ore-paginationnavigationStandardaria-label, aria-current
ore-breadcrumbnavigationStandardaria-label, aria-current
ore-avatarNonealt or aria-label

Layout

ComponentNotes
ore-sidebarNavigation landmark — provide aria-label for screen readers
ore-navbarNavigation landmark — provide aria-label for screen readers
ore-gridLayout only, no interactive semantics
ore-boxLayout only, no interactive semantics

Compliance Contract

Every published component must satisfy:

RequirementStandard
Keyboard navigabilityWCAG 2.1 AA §2.1
Visible focus indicatorWCAG 2.1 AA §2.4.7
Colour contrast ≥ 4.5:1 (normal text)WCAG 2.1 AA §1.4.3
Colour contrast ≥ 3:1 (large text / UI components)WCAG 2.1 AA §1.4.11
Accessible name on every interactive controlWCAG 2.1 AA §4.1.2
Correct ARIA roles and statesWCAG 2.1 AA §4.1.2
Live region announcements for dynamic changesWCAG 2.1 AA §4.1.3
Touch target ≥ 44×44 CSS pxWCAG 2.2 §2.5.8
Forced-colors / Windows High ContrastWCAG §1.4.3 enhanced
Reduced-motion fallbackWCAG 2.1 §2.3.3

Known Gaps

AreaGapPlanned
Visual regressionNo snapshot CI yetPlaywright visual diff in vNext
NVDA + JAWS parityNot systematically testedManual audit before 2.0 stable
ore-select virtual listVirtual items need aria-setsize / aria-posinsetTracked