Skip to content

Commit 44ef8fa

Browse files
authored
feat: accessible descriptions and labels for various components (#674)
* feat: added descriptions for content buttons, links, basic cards, caption
1 parent b5be2da commit 44ef8fa

File tree

13 files changed

+79
-13
lines changed

13 files changed

+79
-13
lines changed

src/blocks/Header/Header.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import React, {useContext} from 'react';
22

3+
import {useUniqId} from '@gravity-ui/uikit';
4+
35
import {Button, HTML, Media, RouterLink} from '../../components';
46
import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs/HeaderBreadcrumbs';
57
import {getMediaImage} from '../../components/Media/Image/utils';
@@ -96,6 +98,7 @@ export const HeaderBlock = (props: WithChildren<HeaderBlockFullProps>) => {
9698
const imageThemed = image && getThemedValue(image, theme);
9799
const videoThemed = video && getThemedValue(video, theme);
98100
const fullWidth = backgroundThemed?.fullWidth || backgroundThemed?.fullWidthMedia;
101+
const titleId = useUniqId();
99102

100103
return (
101104
<header
@@ -134,7 +137,7 @@ export const HeaderBlock = (props: WithChildren<HeaderBlockFullProps>) => {
134137
<HTML>{overtitle}</HTML>
135138
</div>
136139
)}
137-
<h1 className={b('title')}>
140+
<h1 className={b('title')} id={titleId}>
138141
{status}
139142
{renderTitle ? renderTitle(title) : <HTML>{title}</HTML>}
140143
</h1>
@@ -157,6 +160,9 @@ export const HeaderBlock = (props: WithChildren<HeaderBlockFullProps>) => {
157160
key={index}
158161
className={b('button')}
159162
size="xl"
163+
extraProps={{
164+
'aria-describedby': titleId,
165+
}}
160166
{...button}
161167
/>
162168
</RouterLink>

src/blocks/Tabs/Tabs.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import React, {Fragment, useRef, useState} from 'react';
22

3+
import {useUniqId} from '@gravity-ui/uikit';
4+
35
import AnimateBlock from '../../components/AnimateBlock/AnimateBlock';
46
import ButtonTabs, {ButtonTabsItemProps} from '../../components/ButtonTabs/ButtonTabs';
57
import FullscreenImage from '../../components/FullscreenImage/FullscreenImage';
@@ -36,13 +38,19 @@ export const TabsBlock = ({
3638
const ref = useRef<HTMLDivElement>(null);
3739
const mediaWidth = ref?.current?.offsetWidth;
3840
const mediaHeight = mediaWidth && getHeight(mediaWidth);
41+
const captionId = useUniqId();
3942

4043
let imageProps;
4144

4245
if (activeTabData) {
4346
const themedImage = getThemedValue(activeTabData.image, theme);
4447

4548
imageProps = themedImage && getMediaImage(themedImage);
49+
if (activeTabData.caption && imageProps) {
50+
Object.assign(imageProps, {
51+
'aria-describedby': captionId,
52+
});
53+
}
4654
}
4755

4856
const showMedia = Boolean(activeTabData?.media || imageProps);
@@ -99,7 +107,11 @@ export const TabsBlock = ({
99107
<FullscreenImage {...imageProps} imageClassName={b('image')} />
100108
</Fragment>
101109
)}
102-
{activeTabData?.caption && <p className={b('caption')}>{activeTabData.caption}</p>}
110+
{activeTabData?.caption && (
111+
<p className={b('caption')} id={captionId}>
112+
{activeTabData.caption}
113+
</p>
114+
)}
103115
</Col>
104116
);
105117

src/components/BackLink/BackLink.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {ReactNode, useCallback, useContext} from 'react';
1+
import React, {HTMLProps, ReactNode, useCallback, useContext} from 'react';
22

33
import {Button, ButtonSize, Icon} from '@gravity-ui/uikit';
44

@@ -9,14 +9,15 @@ import {DefaultEventNames, Tabbable} from '../../models';
99

1010
export type Theme = 'default' | 'special';
1111

12-
export interface BackLinkProps extends Tabbable {
12+
export interface BackLinkProps<T = HTMLElement> extends Tabbable {
1313
url: string;
1414
title: ReactNode;
1515
theme?: Theme;
1616
size?: ButtonSize;
1717
className?: string;
1818
shouldHandleBackAction?: boolean;
1919
onClick?: () => void;
20+
extraProps?: HTMLProps<T>;
2021
}
2122

2223
export default function BackLink(props: BackLinkProps) {
@@ -30,6 +31,7 @@ export default function BackLink(props: BackLinkProps) {
3031
shouldHandleBackAction = false,
3132
onClick,
3233
tabIndex,
34+
extraProps,
3335
} = props;
3436
const handleAnalytics = useAnalytics(DefaultEventNames.ShareButton, url);
3537

@@ -59,6 +61,7 @@ export default function BackLink(props: BackLinkProps) {
5961
href={shouldHandleBackAction ? undefined : url}
6062
onClick={shouldHandleBackAction ? backActionHandler : undefined}
6163
tabIndex={tabIndex}
64+
extraProps={extraProps}
6265
>
6366
<Icon data={ArrowSidebar} size={24} />
6467
<span>{title}</span>

src/components/Button/Button.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import './Button.scss';
1818
export interface ButtonProps extends Omit<ButtonParams, 'url'>, QAProps {
1919
className?: string;
2020
url?: string;
21-
urlTitle?: string;
2221
onClick?: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>;
2322
}
2423

src/components/FileLink/FileLink.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const FileLink = (props: WithChildren<FileLinkProps>) => {
5757
onClick,
5858
tabIndex,
5959
urlTitle,
60+
extraProps,
6061
} = props;
6162
const fileExt = getFileExt(href) as FileExtension;
6263
const labelTheme = (FileExtensionThemes[fileExt] || 'unknown') as LabelProps['theme'];
@@ -74,6 +75,7 @@ const FileLink = (props: WithChildren<FileLinkProps>) => {
7475
tabIndex={tabIndex}
7576
title={urlTitle}
7677
{...getLinkProps(href, hostname)}
78+
{...extraProps}
7779
>
7880
{text}
7981
</a>

src/components/FullscreenImage/FullscreenImage.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {CSSProperties, useState} from 'react';
1+
import React, {CSSProperties, HTMLProps, useState} from 'react';
22

33
import {Icon, Modal} from '@gravity-ui/uikit';
44

@@ -14,21 +14,22 @@ export interface FullscreenImageProps extends ImageProps {
1414
imageClassName?: string;
1515
modalImageClass?: string;
1616
imageStyle?: CSSProperties;
17+
extraProps?: HTMLProps<HTMLDivElement>;
1718
}
1819

1920
const b = block('fullscreen-image');
2021
const FULL_SCREEN_ICON_SIZE = 18;
2122
const CLOSE_ICON_SIZE = 30;
2223

2324
const FullscreenImage = (props: FullscreenImageProps) => {
24-
const {imageClassName, modalImageClass, imageStyle, alt = i18n('img-alt')} = props;
25+
const {imageClassName, modalImageClass, imageStyle, alt = i18n('img-alt'), extraProps} = props;
2526
const [isOpened, setIsOpened] = useState(false);
2627

2728
const openModal = () => setIsOpened(true);
2829
const closeModal = () => setIsOpened(false);
2930

3031
return (
31-
<div className={b()}>
32+
<div className={b()} {...extraProps}>
3233
<div className={b('image-wrapper')}>
3334
<Image
3435
{...props}

src/components/Image/Image.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const Image = (props: ImageProps) => {
5757
onClick,
5858
containerClassName,
5959
qa,
60+
...rest
6061
} = props;
6162
const [imgLoadingError, setImgLoadingError] = useState(false);
6263

@@ -113,6 +114,7 @@ const Image = (props: ImageProps) => {
113114
style={style}
114115
onClick={onClick}
115116
onError={() => setImgLoadingError(true)}
117+
{...rest}
116118
/>
117119
</picture>
118120
);

src/components/Link/Link.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const LinkBlock = (props: WithChildren<LinkFullProps>) => {
5858
tabIndex,
5959
qa,
6060
urlTitle,
61+
extraProps,
6162
} = props;
6263
const qaAttributes = getQaAttrubutes(qa, ['normal']);
6364

@@ -82,6 +83,7 @@ const LinkBlock = (props: WithChildren<LinkFullProps>) => {
8283
url={href}
8384
onClick={onClick}
8485
tabIndex={tabIndex}
86+
extraProps={extraProps}
8587
/>
8688
);
8789
case 'file-link':
@@ -94,6 +96,7 @@ const LinkBlock = (props: WithChildren<LinkFullProps>) => {
9496
textSize={textSize}
9597
onClick={onClick}
9698
tabIndex={tabIndex}
99+
extraProps={extraProps}
97100
/>
98101
);
99102
case 'normal': {
@@ -109,6 +112,7 @@ const LinkBlock = (props: WithChildren<LinkFullProps>) => {
109112
title={urlTitle}
110113
{...linkProps}
111114
data-qa={qaAttributes.normal}
115+
{...extraProps}
112116
>
113117
{arrow ? (
114118
<Fragment>

src/components/Title/Title.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ const b = block('title');
1313

1414
export interface TitleProps extends TitleParams {
1515
colSizes?: GridColumnSizesType;
16+
id?: string;
1617
}
1718

1819
const Title = ({
1920
title,
2021
subtitle,
2122
className,
2223
colSizes = {all: 12, sm: 8},
24+
id,
2325
}: TitleProps & ClassNameProps) => {
2426
if (!title && !subtitle) {
2527
return null;
@@ -29,7 +31,7 @@ const Title = ({
2931
!title || typeof title === 'string' ? ({text: title} as TitleItemProps) : title;
3032

3133
return (
32-
<div className={b(null, className)}>
34+
<div className={b(null, className)} id={id}>
3335
{text && (
3436
<Col reset sizes={colSizes}>
3537
<TitleItem text={text} {...titleProps} />

src/models/constructor-items/blocks.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,9 @@ export interface ContentItemProps {
352352

353353
export interface ContentBlockProps {
354354
title?: TitleItemBaseProps | string;
355+
titleId?: string;
355356
text?: string;
357+
textId?: string;
356358
additionalInfo?: string;
357359
links?: LinkProps[];
358360
buttons?: ButtonProps[];

0 commit comments

Comments
 (0)