From 4e82c4c2f7d12e36a4ffca44ad33b4c3357dc353 Mon Sep 17 00:00:00 2001 From: Bea Esguerra Date: Tue, 25 Jun 2024 09:40:09 -0600 Subject: [PATCH] Improve a11y attributes and support for id props in dropdown components (#2257) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary: - ActionMenu: Adds new optional props: `id` and `dropdownId`. If not provided, they are auto-generated. Ids are applied and the dropdownId is now used for the `aria-controls` attribute for the opener - SingleSelect and MultiSelect: Adds optional `dropdownId` prop. If `id` or `dropdownId` props are not provided, ids for these will be auto-generated. The opener's `aria-controls` attribute is set to the dropdown id - Make sure default and custom openers have all the correct attributes (`aria-haspopup`, `aria-expanded`). This addresses warnings in the Storybook a11y add on Issue: WB-1714 ## Test plan: - Review documentation ActionMenu, SingleSelect, and MultiSelect - `id` and `dropdownId` props - Docs for `With Custom Opener` example - Confirm in ActionMenu, SingleSelect, and MultiSelect: - When the `id` and `dropdownId` props are not set, there is an auto-generated id for each of these on the opener and the dropdown. The opener should also have `aria-controls` set to the dropdown id - When the `id` and `dropdownId` props are set, they should be the id on the opener and the dropdown elements. The opener should also have `aria-controls` set to the provided `dropdownId` - The opener should have the `aria-haspopup` and `aria-expanded` attributes set - All of the above should apply also when a custom opener is used Author: beaesguerra Reviewers: jandrade Required Reviewers: Approved By: jandrade Checks: ✅ codecov/project, ✅ Lint (ubuntu-latest, 20.x), ✅ Check build sizes (ubuntu-latest, 20.x), ✅ Test (ubuntu-latest, 20.x, 2/2), ✅ Test (ubuntu-latest, 20.x, 1/2), ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Prime node_modules cache for primary configuration (ubuntu-latest, 20.x), ✅ gerald, ✅ Chromatic - Get results on regular PRs (ubuntu-latest, 20.x), ✅ Test (ubuntu-latest, 20.x, 2/2), ✅ Lint (ubuntu-latest, 20.x), ✅ Test (ubuntu-latest, 20.x, 1/2), ✅ Check build sizes (ubuntu-latest, 20.x), ✅ Chromatic - Build on regular PRs / chromatic (ubuntu-latest, 20.x), ⏭️ Publish npm snapshot, ⏭️ Chromatic - Skip on Release PR (changesets), ✅ Prime node_modules cache for primary configuration (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ gerald, ⏭️ dependabot Pull Request URL: https://github.com/Khan/wonder-blocks/pull/2257 --- .changeset/ninety-dogs-push.md | 17 + .../action-menu.stories.tsx | 4 + .../base-select.argtypes.ts | 18 +- .../multi-select.stories.tsx | 3 + .../single-select.stories.tsx | 3 + .../components/__tests__/action-menu.test.tsx | 309 ++++++++++++++++-- .../__tests__/multi-select.test.tsx | 293 +++++++++++++++++ .../__tests__/single-select.test.tsx | 306 +++++++++++++++++ .../src/components/action-menu.tsx | 123 ++++--- .../src/components/dropdown-core.tsx | 6 + .../src/components/dropdown-opener.tsx | 18 +- .../src/components/multi-select.tsx | 155 +++++---- .../src/components/single-select.tsx | 144 ++++---- 13 files changed, 1210 insertions(+), 189 deletions(-) create mode 100644 .changeset/ninety-dogs-push.md diff --git a/.changeset/ninety-dogs-push.md b/.changeset/ninety-dogs-push.md new file mode 100644 index 000000000..935fd5c00 --- /dev/null +++ b/.changeset/ninety-dogs-push.md @@ -0,0 +1,17 @@ +--- +"@khanacademy/wonder-blocks-dropdown": minor +--- + +Improves support for providing ids to the opener and dropdown elements. These ids are auto-generated if they are not provided. + +Also applies attributes to elements automatically for improved accessibility (`aria-controls`, `aria-haspopup`, `aria-expanded`). + +- `ActionMenu` + - Adds new `dropdownId` and `id` props. If these are not provided, these ids will be generated automatically + - `aria-controls` is set to the dropdown id for both default and custom openers + - Ensure `aria-haspopup` and `aria-expanded` attributes are set on both default and custom openers +- `SingleSelect` and `MultiSelect` + - Adds new `dropdownId` prop. If this is not provided, an id will be generated automatically + - If the `id` prop is not provided, an id for the component is now generated automatically + - `aria-controls` is set to the dropdown id for both default and custom openers + - Ensure `id`, `aria-haspopup` and `aria-expanded` attributes are set on both default and custom openers diff --git a/__docs__/wonder-blocks-dropdown/action-menu.stories.tsx b/__docs__/wonder-blocks-dropdown/action-menu.stories.tsx index 9618c9c80..4aef5bc08 100644 --- a/__docs__/wonder-blocks-dropdown/action-menu.stories.tsx +++ b/__docs__/wonder-blocks-dropdown/action-menu.stories.tsx @@ -358,6 +358,9 @@ export const Controlled: StoryComponentType = { * * **Note:** If you need to use a custom ID for testing the opener, make sure to * pass the testId prop inside the opener component/element. + * + * **Accessibility:** When a custom opener is used, the following attributes are + * added automatically: `aria-expanded`, `aria-haspopup`, and `aria-controls`. */ export const CustomOpener: StoryComponentType = { @@ -375,6 +378,7 @@ export const CustomOpener: StoryComponentType = { hovered && styles.hovered, pressed && styles.pressed, ]} + role="button" > {text} diff --git a/__docs__/wonder-blocks-dropdown/base-select.argtypes.ts b/__docs__/wonder-blocks-dropdown/base-select.argtypes.ts index de194e6ba..d15d74d64 100644 --- a/__docs__/wonder-blocks-dropdown/base-select.argtypes.ts +++ b/__docs__/wonder-blocks-dropdown/base-select.argtypes.ts @@ -117,8 +117,22 @@ const argTypes: ArgTypes = { control: {type: "text"}, description: `Unique identifier attached to the field control. If used, we need to guarantee that the ID is unique within everything - rendered on a page. Used to match \`