Skip to content

Commit a5eb44d

Browse files
committed
Fix Carousel ria-labelledby target missing when title prop not provided
1 parent de79092 commit a5eb44d

4 files changed

Lines changed: 176 additions & 67 deletions

File tree

axe-results-incomplete.json

Lines changed: 160 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,175 @@
2121
{
2222
"id": "aria-valid-attr-value",
2323
"data": {
24-
"messageKey": "controlsWithinPopup",
25-
"needsReview": "aria-controls=\"theme-picker-panel\""
24+
"messageKey": "noId",
25+
"needsReview": "aria-labelledby=\"carousel-articles-suggested-all-title\""
2626
},
2727
"relatedNodes": [],
2828
"impact": "critical",
29-
"message": "Unable to determine if aria-controls referenced ID exists on the page while using aria-haspopup: aria-controls=\"theme-picker-panel\""
29+
"message": "ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
3030
}
3131
],
3232
"none": [],
3333
"impact": "critical",
34-
"html": "<button class=\"theme-toggle-btn the...\" type=\"button\" aria-expanded=\"false\" aria-controls=\"theme-picker-panel\" aria-label=\"toggle theme switche...\" aria-haspopup=\"true\" data-theme-toggle=\"\">",
34+
"html": "<div class=\"embla relative\" role=\"region\" aria-labelledby=\"carousel-articles-suggested-all-title\" data-astro-cid-kfjqoxel=\"\">",
3535
"target": [
36-
".theme-toggle-btn"
36+
".mb-0:nth-child(1) > carousel-slider > .py-8.lg\\:px-8.px-4 > .embla.relative[role=\"region\"]"
3737
],
38-
"failureSummary": "Fix all of the following:\n Unable to determine if aria-controls referenced ID exists on the page while using aria-haspopup: aria-controls=\"theme-picker-panel\""
38+
"failureSummary": "Fix all of the following:\n ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
39+
},
40+
{
41+
"any": [],
42+
"all": [
43+
{
44+
"id": "aria-valid-attr-value",
45+
"data": {
46+
"messageKey": "noId",
47+
"needsReview": "aria-labelledby=\"carousel-articles-suggested-all-title\""
48+
},
49+
"relatedNodes": [],
50+
"impact": "critical",
51+
"message": "ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
52+
}
53+
],
54+
"none": [],
55+
"impact": "critical",
56+
"html": "<div class=\"embla relative\" role=\"region\" aria-labelledby=\"carousel-articles-suggested-all-title\" data-astro-cid-kfjqoxel=\"\">",
57+
"target": [
58+
".mb-0:nth-child(2) > carousel-slider > .py-8.lg\\:px-8.px-4 > .embla.relative[role=\"region\"]"
59+
],
60+
"failureSummary": "Fix all of the following:\n ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
61+
},
62+
{
63+
"any": [],
64+
"all": [
65+
{
66+
"id": "aria-valid-attr-value",
67+
"data": {
68+
"messageKey": "noId",
69+
"needsReview": "aria-labelledby=\"carousel-articles-suggested-all-title\""
70+
},
71+
"relatedNodes": [],
72+
"impact": "critical",
73+
"message": "ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
74+
}
75+
],
76+
"none": [],
77+
"impact": "critical",
78+
"html": "<div class=\"embla relative\" role=\"region\" aria-labelledby=\"carousel-articles-suggested-all-title\" data-astro-cid-kfjqoxel=\"\">",
79+
"target": [
80+
".mb-0:nth-child(3) > carousel-slider > .py-8.lg\\:px-8.px-4 > .embla.relative[role=\"region\"]"
81+
],
82+
"failureSummary": "Fix all of the following:\n ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
83+
},
84+
{
85+
"any": [],
86+
"all": [
87+
{
88+
"id": "aria-valid-attr-value",
89+
"data": {
90+
"messageKey": "noId",
91+
"needsReview": "aria-labelledby=\"carousel-articles-suggested-all-title\""
92+
},
93+
"relatedNodes": [],
94+
"impact": "critical",
95+
"message": "ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
96+
}
97+
],
98+
"none": [],
99+
"impact": "critical",
100+
"html": "<div class=\"embla relative\" role=\"region\" aria-labelledby=\"carousel-articles-suggested-all-title\" data-astro-cid-kfjqoxel=\"\">",
101+
"target": [
102+
".mb-0:nth-child(4) > carousel-slider > .py-8.lg\\:px-8.px-4 > .embla.relative[role=\"region\"]"
103+
],
104+
"failureSummary": "Fix all of the following:\n ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
105+
},
106+
{
107+
"any": [],
108+
"all": [
109+
{
110+
"id": "aria-valid-attr-value",
111+
"data": {
112+
"messageKey": "noId",
113+
"needsReview": "aria-labelledby=\"carousel-articles-suggested-all-title\""
114+
},
115+
"relatedNodes": [],
116+
"impact": "critical",
117+
"message": "ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
118+
}
119+
],
120+
"none": [],
121+
"impact": "critical",
122+
"html": "<div class=\"embla relative\" role=\"region\" aria-labelledby=\"carousel-articles-suggested-all-title\" data-astro-cid-kfjqoxel=\"\">",
123+
"target": [
124+
".mb-0:nth-child(5) > carousel-slider > .py-8.lg\\:px-8.px-4 > .embla.relative[role=\"region\"]"
125+
],
126+
"failureSummary": "Fix all of the following:\n ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
127+
},
128+
{
129+
"any": [],
130+
"all": [
131+
{
132+
"id": "aria-valid-attr-value",
133+
"data": {
134+
"messageKey": "noId",
135+
"needsReview": "aria-labelledby=\"carousel-articles-suggested-all-title\""
136+
},
137+
"relatedNodes": [],
138+
"impact": "critical",
139+
"message": "ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
140+
}
141+
],
142+
"none": [],
143+
"impact": "critical",
144+
"html": "<div class=\"embla relative\" role=\"region\" aria-labelledby=\"carousel-articles-suggested-all-title\" data-astro-cid-kfjqoxel=\"\">",
145+
"target": [
146+
".mb-0:nth-child(6) > carousel-slider > .py-8.lg\\:px-8.px-4 > .embla.relative[role=\"region\"]"
147+
],
148+
"failureSummary": "Fix all of the following:\n ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
149+
},
150+
{
151+
"any": [],
152+
"all": [
153+
{
154+
"id": "aria-valid-attr-value",
155+
"data": {
156+
"messageKey": "noId",
157+
"needsReview": "aria-labelledby=\"carousel-articles-suggested-all-title\""
158+
},
159+
"relatedNodes": [],
160+
"impact": "critical",
161+
"message": "ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
162+
}
163+
],
164+
"none": [],
165+
"impact": "critical",
166+
"html": "<div class=\"embla relative\" role=\"region\" aria-labelledby=\"carousel-articles-suggested-all-title\" data-astro-cid-kfjqoxel=\"\">",
167+
"target": [
168+
".mb-0:nth-child(7) > carousel-slider > .py-8.lg\\:px-8.px-4 > .embla.relative[role=\"region\"]"
169+
],
170+
"failureSummary": "Fix all of the following:\n ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
171+
},
172+
{
173+
"any": [],
174+
"all": [
175+
{
176+
"id": "aria-valid-attr-value",
177+
"data": {
178+
"messageKey": "noId",
179+
"needsReview": "aria-labelledby=\"carousel-articles-suggested-all-title\""
180+
},
181+
"relatedNodes": [],
182+
"impact": "critical",
183+
"message": "ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
184+
}
185+
],
186+
"none": [],
187+
"impact": "critical",
188+
"html": "<div class=\"embla relative\" role=\"region\" aria-labelledby=\"carousel-articles-suggested-all-title\" data-astro-cid-kfjqoxel=\"\">",
189+
"target": [
190+
".mb-0:nth-child(8) > carousel-slider > .py-8.lg\\:px-8.px-4 > .embla.relative[role=\"region\"]"
191+
],
192+
"failureSummary": "Fix all of the following:\n ARIA attribute element ID does not exist on the page: aria-labelledby=\"carousel-articles-suggested-all-title\""
39193
}
40194
]
41195
}

axe-results-violations.json

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1 @@
1-
[
2-
{
3-
"id": "aria-tooltip-name",
4-
"impact": "serious",
5-
"tags": [
6-
"cat.aria",
7-
"wcag2a",
8-
"wcag412",
9-
"EN-301-549",
10-
"EN-9.4.1.2"
11-
],
12-
"description": "Ensure every ARIA tooltip node has an accessible name",
13-
"help": "ARIA tooltip nodes must have an accessible name",
14-
"helpUrl": "https://dequeuniversity.com/rules/axe/4.11/aria-tooltip-name?application=playwright",
15-
"nodes": [
16-
{
17-
"any": [
18-
{
19-
"id": "has-visible-text",
20-
"data": null,
21-
"relatedNodes": [],
22-
"impact": "serious",
23-
"message": "Element does not have text that is visible to screen readers"
24-
},
25-
{
26-
"id": "aria-label",
27-
"data": null,
28-
"relatedNodes": [],
29-
"impact": "serious",
30-
"message": "aria-label attribute does not exist or is empty"
31-
},
32-
{
33-
"id": "aria-labelledby",
34-
"data": null,
35-
"relatedNodes": [],
36-
"impact": "serious",
37-
"message": "aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty"
38-
},
39-
{
40-
"id": "non-empty-title",
41-
"data": {
42-
"messageKey": "noAttr"
43-
},
44-
"relatedNodes": [],
45-
"impact": "serious",
46-
"message": "Element has no title attribute"
47-
}
48-
],
49-
"all": [],
50-
"none": [],
51-
"impact": "serious",
52-
"html": "<div data-theme-tooltip-portal=\"true\" id=\"theme-picker-tooltip\" role=\"tooltip\" class=\"fixed left-0 top-0 z-(--z-theme-picker) pointer-events-none opacity-0 transition-opacity duration-150 ease-out\">",
53-
"target": [
54-
"#theme-picker-tooltip"
55-
],
56-
"failureSummary": "Fix any of the following:\n Element does not have text that is visible to screen readers\n aria-label attribute does not exist or is empty\n aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty\n Element has no title attribute"
57-
}
58-
]
59-
}
60-
]
1+
[]

src/components/Carousel/client/__tests__/index.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,19 @@ describe('Carousel component (server output)', () => {
201201
)
202202
})
203203

204+
it('does not emit aria-labelledby when no title is provided', async () => {
205+
await renderCarousel(
206+
({ root }) => {
207+
const heading = root.querySelector('h2')
208+
const region = root.querySelector('.embla')
209+
210+
expect(heading).toBeNull()
211+
expect(region?.getAttribute('aria-labelledby')).toBeNull()
212+
},
213+
{ title: undefined, variant: 'suggested', currentSlug: undefined }
214+
)
215+
})
216+
204217
it('assigns aria-controls to pagination dots and navigation buttons', async () => {
205218
await renderCarousel(({ root }) => {
206219
const viewport = root.querySelector('.embla__viewport')

src/components/Carousel/index.astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ const allItems: ItemType[] = itemsOverride
7373
const items = prepareItems(allItems, variant, currentSlug, limit)
7474
7575
const carouselId = `carousel-${type}-${variant}-${currentSlug ?? 'all'}`
76+
const carouselRegionLabelledBy = title ? `${carouselId}-title` : undefined
7677
---
7778

7879
{
@@ -98,7 +99,7 @@ const carouselId = `carousel-${type}-${variant}-${currentSlug ?? 'all'}`
9899
)}
99100

100101
{/* Embla Carousel */}
101-
<div class="embla relative" role="region" aria-labelledby={`${carouselId}-title`}>
102+
<div class="embla relative" role="region" aria-labelledby={carouselRegionLabelledBy}>
102103
<div class="embla__viewport overflow-hidden p-4">
103104
<div class="embla__container flex -ml-4 md:-ml-6">
104105
{items.map((item: ItemType, index) => (

0 commit comments

Comments
 (0)