diff --git a/.claude/skills/contributing/references/a11y-review.md b/.claude/skills/contributing/references/a11y-review.md index d01d1c234..6bb91b1fd 100644 --- a/.claude/skills/contributing/references/a11y-review.md +++ b/.claude/skills/contributing/references/a11y-review.md @@ -2,6 +2,10 @@ Target component: `$ARGUMENTS` +## Standard + +TEDI follows EN 301 549 and, for web content, **WCAG 2.2 level AA**. Review against WCAG 2.2 AA. Components released before TEDI moved to WCAG 2.2 were built against WCAG 2.1 AA, so check the criteria new in 2.2 explicitly (2.4.11 Focus Not Obscured, 2.5.7 Dragging Movements, 2.5.8 Target Size) and report a failure as a Major finding like any other AA violation. The [accessibility page on tedi.ee](https://www.tedi.ee/1ee8444b7/p/33df89-sissejuhatus/b/05a2e8) is the canonical statement. + ## Audit Procedure ### 1. Read the Component @@ -39,6 +43,7 @@ Check against WAI-ARIA Authoring Practices for the component pattern: - [ ] Focus returns to trigger element when overlay closes - [ ] `tabIndex={-1}` used for programmatically focusable non-interactive elements - [ ] No focus on hidden/invisible elements +- [ ] Focused element is not fully hidden behind sticky headers, overlays or other content (WCAG 2.4.11, AA) - [ ] Uses `FloatingFocusManager` for overlay focus trapping (floating-ui pattern) ### 5. Visual & Motion @@ -51,8 +56,8 @@ Check against WAI-ARIA Authoring Practices for the component pattern: ### 6. Touch & Pointer -- [ ] Touch targets minimum 44x44 CSS pixels -- [ ] Adequate spacing between touch targets +- [ ] Pointer targets (mouse, touch, stylus) at least 24x24 CSS pixels, or enough spacing around smaller targets (WCAG 2.5.8, AA); prefer 44x44 (WCAG 2.5.5, AAA) +- [ ] Anything done by dragging can also be done with a single pointer without dragging, e.g. clicks or taps, possibly several (WCAG 2.5.7, AA). Exceptions: dragging is essential, or the behavior comes from the browser and is not modified by the component - [ ] No functionality dependent on hover alone (touch devices can't hover) - [ ] Uses `useIsTouchDevice()` hook where applicable for touch-specific behavior diff --git a/.github/ISSUE_TEMPLATE/new-tedi-ready-component.md b/.github/ISSUE_TEMPLATE/new-tedi-ready-component.md index 9bb56f481..21ff23b1b 100644 --- a/.github/ISSUE_TEMPLATE/new-tedi-ready-component.md +++ b/.github/ISSUE_TEMPLATE/new-tedi-ready-component.md @@ -21,13 +21,18 @@ Design: - [ ] CodeCov passes its threshold _(80% on the changed code, with 10% tolerance — a separate gate from the Jest one above)_ - [ ] The component has passed **code review** - [ ] The component has passed **Chromatic visual review** +- [ ] The component has passed the **automated accessibility tests** _(axe checks on the Storybook stories, run in CI)_ +- [ ] The component has been manually tested against **WCAG 2.2 AA** _(see [Ligipääsetavus](https://www.tedi.ee/1ee8444b7/p/33df89-sissejuhatus/b/05a2e8))_ +- [ ] The component has been manually tested in **Chrome, Firefox, Safari and Edge**, and on **iOS and Android** devices - [ ] **Storybook stories** are created: - [ ] Cover all Figma variations - [ ] Include edge cases, empty/error states - [ ] Component’s **API (props, slots, events)** is documented -- [ ] **ZeroHeight is updated** with design/development guidelines +- [ ] **Zeroheight is updated** with design/development guidelines +- [ ] WCAG guidelines for the component are documented in Zeroheight - [ ] **External dependencies** used in the component are documented in **Storybook and Zeroheight**, with rationale - [ ] **Semantic commit format** `type(scope): Subject text #issue-ref` is used (for `semantic-release`), with the **issue reference required** - see [Commit convention](https://github.com/TEDI-Design-System/general/wiki/Commit-convention) - [ ] External libraries **comply with [validated open source licenses](https://github.com/TEDI-Design-System/general/wiki/Definition-of-Done#validated-open-source-component-licences)** - [ ] Component is versioned correctly and ready for release if required - [ ] Update the **React** development status on the [statuses page in Zeroheight](https://www.tedi.ee/1ee8444b7/p/300e17-komponentide-staatused) +- [ ] Update the **WCAG** status on the [statuses page in Zeroheight](https://www.tedi.ee/1ee8444b7/p/300e17-komponentide-staatused) diff --git a/.github/ISSUE_TEMPLATE/react-tedi-ready-component-issue.md b/.github/ISSUE_TEMPLATE/react-tedi-ready-component-issue.md index 03f13ef1c..f8848e6ae 100644 --- a/.github/ISSUE_TEMPLATE/react-tedi-ready-component-issue.md +++ b/.github/ISSUE_TEMPLATE/react-tedi-ready-component-issue.md @@ -28,13 +28,18 @@ assignees: '' - [ ] CodeCov passes its threshold _(80% on the changed code, with 10% tolerance — a separate gate from the Jest one above)_ - [ ] The component has passed **code review** - [ ] The component has passed **Chromatic visual review** +- [ ] The component has passed the **automated accessibility tests** _(axe checks on the Storybook stories, run in CI)_ +- [ ] The component has been manually tested against **WCAG 2.2 AA** _(see [Ligipääsetavus](https://www.tedi.ee/1ee8444b7/p/33df89-sissejuhatus/b/05a2e8))_ +- [ ] The component has been manually tested in **Chrome, Firefox, Safari and Edge**, and on **iOS and Android** devices - [ ] **Storybook stories** are created: - [ ] Cover all Figma variations - [ ] Include edge cases, empty/error states - [ ] Component’s **API (props, slots, events)** is documented -- [ ] **ZeroHeight is updated** with design/development guidelines +- [ ] **Zeroheight is updated** with design/development guidelines +- [ ] WCAG guidelines for the component are documented in Zeroheight - [ ] **External dependencies** used in the component are documented in **Storybook and Zeroheight**, with rationale - [ ] **Semantic commit format** `type(scope): Subject text #issue-ref` is used (for `semantic-release`), with the **issue reference required** - see [Commit convention](https://github.com/TEDI-Design-System/general/wiki/Commit-convention) - [ ] External libraries **comply with [validated open source licenses](https://github.com/TEDI-Design-System/general/wiki/Definition-of-Done#validated-open-source-component-licences)** - [ ] Component is versioned correctly and ready for release if required - [ ] Update the **React** development status on the [statuses page in Zeroheight](https://www.tedi.ee/1ee8444b7/p/300e17-komponentide-staatused) +- [ ] Update the **WCAG** status on the [statuses page in Zeroheight](https://www.tedi.ee/1ee8444b7/p/300e17-komponentide-staatused) diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 789b391bf..bf407d937 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -64,6 +64,12 @@ const preview: Preview = { viewMode: 'docs', a11y: { test: 'error', + // axe leaves target-size (WCAG 2.2, 2.5.8) off by default. Set via options.rules, not + // config.rules, so stories that override config.rules don't drop it. To turn it off in a + // story, use options.rules too: config.rules can't override it. + options: { + rules: { 'target-size': { enabled: true } }, + }, }, backgrounds: { options: { diff --git a/README.md b/README.md index a90eeadce..df23a7c3b 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,14 @@ Usage instructions and detailed documentation for using the components in your a --- +## Accessibility + +TEDI follows EN 301 549 and, for web content, WCAG 2.2 level AA. Components released before TEDI moved to WCAG 2.2 were built and tested against WCAG 2.1 AA and are being reviewed for the new criteria. + +The [accessibility page on tedi.ee](https://www.tedi.ee/1ee8444b7/p/33df89-sissejuhatus/b/05a2e8) (in Estonian) describes how components are tested, what TEDI covers and what stays with your project, and how to report an accessibility issue. + +--- + ## Getting Started (Using the package) If you are installing `@tedi-design-system/react` in your own project, follow the diff --git a/src/tedi/components/form/input-group/input-group.stories.tsx b/src/tedi/components/form/input-group/input-group.stories.tsx index a09847ca8..29f24591c 100644 --- a/src/tedi/components/form/input-group/input-group.stories.tsx +++ b/src/tedi/components/form/input-group/input-group.stories.tsx @@ -204,6 +204,14 @@ const SearchCategoryPrefixRow = () => { }; export const StartDynamic: Story = { + parameters: { + a11y: { + options: { + // react-select's whole control is the pointer target, so axe flagging its inner input is a false positive. + rules: { 'target-size': { enabled: false } }, + }, + }, + }, render: () => ( diff --git a/src/tedi/components/form/select/select.stories.tsx b/src/tedi/components/form/select/select.stories.tsx index da41dc71a..bc935f618 100644 --- a/src/tedi/components/form/select/select.stories.tsx +++ b/src/tedi/components/form/select/select.stories.tsx @@ -259,6 +259,14 @@ const iconPickerOptions: ISelectOption[] = ( ).map((d, i) => ({ value: String(i + 1), label: d.name, customData: d })); export const ValueType: Story = { + parameters: { + a11y: { + options: { + // react-select's whole control is the pointer target, so axe flagging its inner input is a false positive. + rules: { 'target-size': { enabled: false } }, + }, + }, + }, render: () => (