Skip to content

Commit e8c0ac9

Browse files
tleperouitaim18
andauthored
feat(accordion) add storybook + a11y (#303)
* feat: export AccordionItemProps Co-authored-by: Itai Mizlish <[email protected]> * test(accordion): add story of Accordion * chore: add storybook bundles to gitignore * feat(accordion): add aria-hidden to accordion items * test(accordion): update accordion story with more items * feat(accordion): improve a11y support --------- Co-authored-by: Itai Mizlish <[email protected]>
1 parent 396aeb1 commit e8c0ac9

File tree

3 files changed

+58
-18
lines changed

3 files changed

+58
-18
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,7 @@ testem.log
6363

6464
# System Files
6565
.DS_Store
66-
Thumbs.db
66+
Thumbs.db
67+
68+
# Storybook
69+
**/storybook-static/*
Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,51 @@
11
import { Meta, StoryObj } from 'storybook-framework-qwik';
2-
import { Accordion, AccordionItem, AccordionProps } from './accordion';
3-
import { within, userEvent } from '@storybook/testing-library';
2+
import {
3+
Accordion,
4+
AccordionItem,
5+
AccordionProps,
6+
AccordionItemProps,
7+
} from './accordion';
8+
import { userEvent, within } from '@storybook/testing-library';
49
import { expect } from '@storybook/jest';
510

611
const meta: Meta<AccordionProps> = {
712
component: Accordion,
813
};
914

10-
export default meta;
15+
type Story = StoryObj<{
16+
accordion: AccordionProps;
17+
accordionItem: AccordionItemProps;
18+
}>;
1119

12-
type Story = StoryObj<AccordionProps>;
20+
export default meta;
1321

1422
export const Primary: Story = {
15-
render: () => (
16-
<Accordion>
17-
<AccordionItem label="Item 1">This is a test</AccordionItem>
18-
</Accordion>
23+
args: {
24+
accordionItem: {
25+
label: 'Label of the accordion being tested',
26+
},
27+
},
28+
render: (args) => (
29+
<>
30+
<Accordion>
31+
<AccordionItem label={`${args.accordionItem.label}`}>
32+
Content of the accordion 11
33+
</AccordionItem>
34+
<AccordionItem label={`${args.accordionItem.label} 11`}>
35+
Content of the accordion 12
36+
</AccordionItem>
37+
<AccordionItem label={`${args.accordionItem.label} 13`}>
38+
Content of the accordion 13
39+
</AccordionItem>
40+
<AccordionItem label={`${args.accordionItem.label} 14`}>
41+
Content of the accordion 14
42+
</AccordionItem>
43+
</Accordion>
44+
</>
1945
),
20-
play: async ({ canvasElement }) => {
46+
play: ({ canvasElement, args }) => {
2147
const canvas = within(canvasElement);
22-
23-
await userEvent.click(canvas.getByText('Item 1'));
24-
25-
await expect(canvas.getByText('This is a test')).toBeInTheDocument();
48+
userEvent.click(canvas.getByText(args.accordionItem.label));
49+
expect(canvas.getByText('Content of the accordion 11')).toBeTruthy();
2650
},
2751
};

packages/kit-headless/src/components/accordion/accordion.tsx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
useSignal,
1414
useStore,
1515
useStylesScoped$,
16+
useId,
1617
} from '@builder.io/qwik';
1718

1819
export type AccordionProps = HTMLAttributes<HTMLElement>;
@@ -25,7 +26,7 @@ interface AccordionContextService {
2526
setItemsBoxRef$: QRL<(ref: Signal<HTMLElement | undefined>) => void>;
2627
}
2728

28-
interface AccordionItemProps {
29+
export interface AccordionItemProps {
2930
label: string;
3031
disabled?: boolean;
3132
class?: string;
@@ -73,11 +74,17 @@ export const AccordionItem = component$((props: AccordionItemProps) => {
7374
}
7475
`);
7576
const contextService = useContext(accordionContext);
77+
const ref = useSignal<HTMLElement>();
78+
const id = useId();
79+
7680
return (
77-
<div class="item">
81+
<div ref={ref} class="item">
7882
<button
83+
id={`${id}__trigger`}
84+
aria-controls={`${id}__body`}
85+
aria-expanded={!!ref.value?.getAttribute('open')}
7986
onClick$={(e) => {
80-
const target = (e.target as HTMLElement).parentElement;
87+
const target = ref.value;
8188
contextService.items.forEach((i: HTMLElement) => {
8289
if (target === i) {
8390
return;
@@ -92,7 +99,13 @@ export const AccordionItem = component$((props: AccordionItemProps) => {
9299
>
93100
{props.label}
94101
</button>
95-
<div class="content">
102+
<div
103+
role="region"
104+
id={`${id}__body`}
105+
class="content"
106+
aria-labelledby={`${id}__trigger`}
107+
aria-hidden={!!ref.value?.getAttribute('open')}
108+
>
96109
<Slot />
97110
</div>
98111
</div>

0 commit comments

Comments
 (0)