Skip to content

Commit ffe0963

Browse files
committed
Add carousel aria attributes to front scrollable carousels
1 parent c069378 commit ffe0963

7 files changed

Lines changed: 67 additions & 10 deletions

dotcom-rendering/src/components/FrontSection.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,7 @@ export const FrontSection = ({
758758
isLabs={isLabs}
759759
/>
760760
}
761+
sectionId={sectionId}
761762
collectionBranding={collectionBranding}
762763
/>
763764

dotcom-rendering/src/components/FrontSectionTitle.tsx

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { BrandingLabel } from './BrandingLabel';
1414
type Props = {
1515
title: React.ReactNode;
1616
collectionBranding: CollectionBranding | undefined;
17+
sectionId: string;
1718
};
1819

1920
const titleStyle = css`
@@ -77,7 +78,11 @@ const aboutThisLinkAdvertisingPartnerStyles = css`
7778
color: ${sourcePalette.news[400]};
7879
`;
7980

80-
export const FrontSectionTitle = ({ title, collectionBranding }: Props) => {
81+
export const FrontSectionTitle = ({
82+
title,
83+
collectionBranding,
84+
sectionId,
85+
}: Props) => {
8186
switch (collectionBranding?.kind) {
8287
case 'foundation': {
8388
const {
@@ -117,7 +122,7 @@ export const FrontSectionTitle = ({ title, collectionBranding }: Props) => {
117122

118123
if (isFrontBranding || isContainerBranding) {
119124
return (
120-
<div css={titleStyle}>
125+
<div id={`${sectionId}-title`} css={titleStyle}>
121126
{title}
122127
<div
123128
css={css`
@@ -148,7 +153,7 @@ export const FrontSectionTitle = ({ title, collectionBranding }: Props) => {
148153
<Hide until="leftCol">
149154
<BrandingLabel branding={collectionBranding.branding} />
150155
</Hide>
151-
<div css={titleStyle}>
156+
<div id={`${sectionId}-title`} css={titleStyle}>
152157
<Hide from="leftCol">
153158
<BrandingLabel
154159
branding={collectionBranding.branding}
@@ -171,7 +176,7 @@ export const FrontSectionTitle = ({ title, collectionBranding }: Props) => {
171176
logo.label.toLowerCase() === 'exclusive advertising partner';
172177
if (isFrontBranding || isContainerBranding) {
173178
return (
174-
<div css={titleStyle}>
179+
<div id={`${sectionId}-title`} css={titleStyle}>
175180
{title}
176181
{isAdvertisingPartnerOrExclusive ? (
177182
<hr css={advertisingPartnerDottedBorder} />
@@ -212,10 +217,18 @@ export const FrontSectionTitle = ({ title, collectionBranding }: Props) => {
212217
</div>
213218
);
214219
}
215-
return <div css={titleStyle}>{title}</div>;
220+
return (
221+
<div id={`${sectionId}-title`} css={titleStyle}>
222+
{title}
223+
</div>
224+
);
216225
}
217226
case undefined: {
218-
return <div css={titleStyle}>{title}</div>;
227+
return (
228+
<div id={`${sectionId}-title`} css={titleStyle}>
229+
{title}
230+
</div>
231+
);
219232
}
220233
default: {
221234
assertUnreachable(collectionBranding);

dotcom-rendering/src/components/ScrollableCarousel.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type Props = {
1616
sectionId?: string;
1717
shouldStackCards?: { desktop: boolean; mobile: boolean };
1818
gapSizes?: GapSizes;
19+
isBelowTabletBreakpoint?: boolean;
1920
};
2021

2122
/**
@@ -234,6 +235,7 @@ export const ScrollableCarousel = ({
234235
sectionId,
235236
shouldStackCards = { desktop: false, mobile: false },
236237
gapSizes = { column: 'large', row: 'large' },
238+
isBelowTabletBreakpoint = false,
237239
}: Props) => {
238240
const carouselRef = useRef<HTMLOListElement | null>(null);
239241
const [previousButtonEnabled, setPreviousButtonEnabled] = useState(false);
@@ -369,7 +371,7 @@ export const ScrollableCarousel = ({
369371

370372
return (
371373
<div css={containerStyles}>
372-
<ol
374+
<ul
373375
ref={carouselRef}
374376
css={[
375377
carouselStyles,
@@ -383,9 +385,15 @@ export const ScrollableCarousel = ({
383385
]}
384386
data-heatphan-type="carousel"
385387
onFocus={scrollToCardOnFocus}
388+
{...(isBelowTabletBreakpoint && {
389+
role: 'region',
390+
'aria-roledescription': 'carousel',
391+
'aria-labelledby': `${sectionId}-title`,
392+
'aria-live': 'polite',
393+
})}
386394
>
387395
{children}
388-
</ol>
396+
</ul>
389397

390398
{showNavigation && (
391399
<CarouselNavigationButtons
@@ -412,10 +420,12 @@ ScrollableCarousel.Item = ({
412420
isStackingCarousel = false,
413421
children,
414422
borderColour = palette('--card-border-top'),
423+
isBelowTabletBreakpoint = false,
415424
}: {
416425
isStackingCarousel?: boolean;
417426
children: React.ReactNode;
418427
borderColour?: string;
428+
isBelowTabletBreakpoint?: boolean;
419429
}) => (
420430
<li
421431
css={[
@@ -424,6 +434,10 @@ ScrollableCarousel.Item = ({
424434
? stackedRowLeftBorderStyles(borderColour)
425435
: singleRowLeftBorderStyles(borderColour),
426436
]}
437+
{...(isBelowTabletBreakpoint && {
438+
role: 'group',
439+
'aria-roledescription': 'slide',
440+
})}
427441
>
428442
{children}
429443
</li>

dotcom-rendering/src/components/ScrollableFeature.importable.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { until } from '@guardian/source/foundations';
12
import { ArticleDesign } from '../lib/articleFormat';
3+
import { removeMediaRulePrefix, useMatchMedia } from '../lib/useMatchMedia';
24
import type {
35
AspectRatio,
46
DCRContainerPalette,
@@ -31,14 +33,22 @@ export const ScrollableFeature = ({
3133
aspectRatio,
3234
collectionId,
3335
}: Props) => {
36+
const isBelowTabletBreakpoint = useMatchMedia(
37+
removeMediaRulePrefix(until.tablet),
38+
);
39+
3440
return (
3541
<ScrollableCarousel
3642
carouselLength={trails.length}
3743
visibleCarouselSlidesOnMobile={1}
3844
visibleCarouselSlidesOnTablet={3}
45+
isBelowTabletBreakpoint={isBelowTabletBreakpoint}
3946
>
4047
{trails.map((card, index) => (
41-
<ScrollableCarousel.Item key={card.url}>
48+
<ScrollableCarousel.Item
49+
key={card.url}
50+
isBelowTabletBreakpoint={isBelowTabletBreakpoint}
51+
>
4252
<FeatureCard
4353
linkTo={card.url}
4454
format={card.format}

dotcom-rendering/src/components/ScrollableMedium.importable.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { until } from '@guardian/source/foundations';
12
import { isMediaCard } from '../lib/cardHelpers';
3+
import { removeMediaRulePrefix, useMatchMedia } from '../lib/useMatchMedia';
24
import type {
35
AspectRatio,
46
DCRContainerPalette,
@@ -33,20 +35,28 @@ export const ScrollableMedium = ({
3335
aspectRatio,
3436
sectionId,
3537
}: Props) => {
38+
const isBelowTabletBreakpoint = useMatchMedia(
39+
removeMediaRulePrefix(until.tablet),
40+
);
41+
3642
return (
3743
<ScrollableCarousel
3844
carouselLength={trails.length}
3945
visibleCarouselSlidesOnMobile={2}
4046
visibleCarouselSlidesOnTablet={4}
4147
sectionId={sectionId}
48+
isBelowTabletBreakpoint={isBelowTabletBreakpoint}
4249
>
4350
{trails.map((trail) => {
4451
const imagePosition = isMediaCard(trail.format)
4552
? 'top'
4653
: 'bottom';
4754

4855
return (
49-
<ScrollableCarousel.Item key={trail.url}>
56+
<ScrollableCarousel.Item
57+
key={trail.url}
58+
isBelowTabletBreakpoint={isBelowTabletBreakpoint}
59+
>
5060
<FrontCard
5161
trail={trail}
5262
imageLoading={imageLoading}

dotcom-rendering/src/components/ScrollableSmall.importable.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { until } from '@guardian/source/foundations';
2+
import { removeMediaRulePrefix, useMatchMedia } from '../lib/useMatchMedia';
13
import type {
24
AspectRatio,
35
DCRContainerPalette,
@@ -61,6 +63,10 @@ export const ScrollableSmall = ({
6163
const mobileBottomCards = [1, 3];
6264
const desktopBottomCards = [2, 3];
6365

66+
const isBelowTabletBreakpoint = useMatchMedia(
67+
removeMediaRulePrefix(until.tablet),
68+
);
69+
6470
return (
6571
<ScrollableCarousel
6672
carouselLength={Math.ceil(trails.length / 2)}
@@ -69,12 +75,14 @@ export const ScrollableSmall = ({
6975
sectionId={sectionId}
7076
shouldStackCards={{ desktop: trails.length > 2, mobile: true }}
7177
gapSizes={{ column: 'large', row: 'medium' }}
78+
isBelowTabletBreakpoint={isBelowTabletBreakpoint}
7279
>
7380
{trails.map((trail, index) => {
7481
return (
7582
<ScrollableCarousel.Item
7683
key={trail.url}
7784
isStackingCarousel={true}
85+
isBelowTabletBreakpoint={isBelowTabletBreakpoint}
7886
>
7987
<FrontCard
8088
trail={trail}

dotcom-rendering/src/components/StorylinesSection.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ export const StorylinesSection = ({
609609
</div>
610610
</>
611611
}
612+
sectionId={sectionId}
612613
collectionBranding={undefined}
613614
/>
614615
</div>

0 commit comments

Comments
 (0)