Skip to content

Commit 1f02f0c

Browse files
authored
fix(a11y-tabs): improve a11y compliance of the tabs component [AC-4742] (#1407)
1 parent 7412f5d commit 1f02f0c

3 files changed

Lines changed: 21 additions & 12 deletions

File tree

src/components/Tabs/Tabs.test.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,11 @@ describe("Tabs", () => {
4141
]}
4242
/>,
4343
);
44-
// TODO: use a more appropriate attribute once the issue below is addressed:
45-
// https://github.com/canonical-web-and-design/vanilla-framework/issues/4481
46-
expect(screen.getByRole("link", { name: "label1" })).toHaveAttribute(
44+
expect(screen.getByRole("tab", { name: "label1" })).toHaveAttribute(
4745
"aria-selected",
4846
"true",
4947
);
50-
expect(screen.getByRole("link", { name: "label2" })).toHaveAttribute(
48+
expect(screen.getByRole("tab", { name: "label2" })).toHaveAttribute(
5149
"aria-selected",
5250
"false",
5351
);
@@ -69,9 +67,13 @@ describe("Tabs", () => {
6967
/>,
7068
);
7169
expect(screen.getByRole("navigation")).toHaveClass("nav-class");
72-
expect(screen.getByRole("list")).toHaveClass("list-class");
73-
expect(screen.getByRole("listitem")).toHaveClass("list-item-class");
74-
expect(screen.getByRole("link")).toHaveClass("link-class");
70+
expect(screen.getByRole("tablist")).toHaveClass("list-class");
71+
expect(screen.getByRole("tab", { name: "label1" })).toHaveClass(
72+
"link-class",
73+
);
74+
expect(
75+
screen.getByRole("tab", { name: "label1" }).closest("li"),
76+
).toHaveClass("list-item-class");
7577
});
7678

7779
it("can use custom elements as links", () => {
@@ -86,7 +88,7 @@ describe("Tabs", () => {
8688
]}
8789
/>,
8890
);
89-
expect(screen.getByRole("button", { name: "label1" })).toBeInTheDocument();
91+
expect(screen.getByRole("tab", { name: "label1" })).toBeInTheDocument();
9092
});
9193

9294
it("can use custom components as links", () => {
@@ -109,7 +111,7 @@ describe("Tabs", () => {
109111
/>,
110112
);
111113

112-
expect(screen.queryByRole("link", { name })).not.toBeInTheDocument();
113-
expect(screen.getByRole("button", { name })).toBeInTheDocument();
114+
expect(screen.queryByRole("button", { name })).not.toBeInTheDocument();
115+
expect(screen.getByRole("tab", { name })).toBeInTheDocument();
114116
});
115117
});

src/components/Tabs/Tabs.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const Tabs = <P,>({
5454
}: Props<P>): React.JSX.Element => {
5555
return (
5656
<nav className={classNames("p-tabs", className)}>
57-
<ul className={classNames("p-tabs__list", listClassName)}>
57+
<ul role="tablist" className={classNames("p-tabs__list", listClassName)}>
5858
{links.map((link, i) => {
5959
const {
6060
active,
@@ -69,8 +69,10 @@ const Tabs = <P,>({
6969
<li
7070
className={classNames("p-tabs__item", listItemClassName)}
7171
key={i}
72+
role="none presentation"
7273
>
7374
<Component
75+
role="tab"
7476
aria-selected={active}
7577
className={classNames("p-tabs__link", className)}
7678
data-testid={`tab-link-${label}`}

src/components/Tabs/__snapshots__/Tabs.test.tsx.snap

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[`Tabs renders 1`] = `
44
<div>
@@ -7,27 +7,32 @@ exports[`Tabs renders 1`] = `
77
>
88
<ul
99
class="p-tabs__list"
10+
role="tablist"
1011
>
1112
<li
1213
class="p-tabs__item"
14+
role="none presentation"
1315
>
1416
<a
1517
aria-selected="true"
1618
class="p-tabs__link"
1719
data-testid="tab-link-label1"
1820
href="/path1"
21+
role="tab"
1922
>
2023
label1
2124
</a>
2225
</li>
2326
<li
2427
class="p-tabs__item"
28+
role="none presentation"
2529
>
2630
<a
2731
aria-selected="false"
2832
class="p-tabs__link"
2933
data-testid="tab-link-label2"
3034
href="/path2"
35+
role="tab"
3136
>
3237
label2
3338
</a>

0 commit comments

Comments
 (0)