Skip to content

Commit

Permalink
fix(RadioGroup): add aria-describedby
Browse files Browse the repository at this point in the history
  • Loading branch information
stanjiawang committed Jun 21, 2024
1 parent e6a7edb commit 38da3c8
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 10 deletions.
17 changes: 15 additions & 2 deletions src/components/RadioGroup/RadioGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { FC } from 'react';
import classnames from 'classnames';
import { v4 as uuidV4 } from 'uuid';
import { useRadioGroup } from '@react-aria/radio';
import { useRadioGroupState } from '@react-stately/radio';

Expand Down Expand Up @@ -27,11 +28,23 @@ const RadioGroup: FC<RadioGroupProps> = (props: RadioGroupProps) => {

const state = useRadioGroupState(props);
const { radioGroupProps, labelProps } = useRadioGroup(props, state);
const radioGroupId = id || uuidV4();
const descriptionId = description ? `radio-group-description-${radioGroupId}` : undefined;

return (
<div {...radioGroupProps} className={classnames(className, STYLE.group)} id={id} style={style}>
<div
{...radioGroupProps}
className={classnames(className, STYLE.group)}
id={radioGroupId}
style={style}
aria-describedby={description ? descriptionId : undefined}
>
<span {...labelProps}>{label}</span>
{description && <Text type={TEXT_CONSTANTS.TYPES.BODY_SECONDARY}>{description}</Text>}
{description &&
<Text id={descriptionId} type={TEXT_CONSTANTS.TYPES.BODY_SECONDARY}>
{description}
</Text>
}
<RadioContext.Provider value={state}>
{options &&
options.map((option: string | RadioProps) => {
Expand Down
17 changes: 17 additions & 0 deletions src/components/RadioGroup/RadioGroup.unit.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import userEvent from '@testing-library/user-event';
import RadioGroup from './';
import { STYLE } from './RadioGroup.constants';

jest.mock('uuid', () => {
return {
v4: () => '1',
};
});

describe('<RadioGroup />', () => {
describe('snapshot', () => {
it('should match snapshot', () => {
Expand Down Expand Up @@ -85,6 +91,7 @@ describe('<RadioGroup />', () => {
label="Test Radio Group"
description="The radio group description"
style={style}
id='example-id'
/>
);

Expand Down Expand Up @@ -349,6 +356,16 @@ describe('<RadioGroup />', () => {
expect(radioGroup).toHaveClass(STYLE.group);
});

it('should have provided aria-describedby when description is provided', () => {
expect.assertions(1);

render(<RadioGroup label="Test Radio Group" description="The radio group description" id='example-id' />);

const radioGroup = screen.getByRole('radiogroup');

expect(radioGroup).toHaveAttribute('aria-describedby', 'radio-group-description-example-id');
});

it('should have provided class when className is provided', () => {
expect.assertions(1);

Expand Down
19 changes: 19 additions & 0 deletions src/components/RadioGroup/RadioGroup.unit.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ exports[`<RadioGroup /> snapshot should match snapshot 1`] = `
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand All @@ -23,6 +24,7 @@ exports[`<RadioGroup /> snapshot should match snapshot when rendered with a mix
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -68,6 +70,7 @@ exports[`<RadioGroup /> snapshot should match snapshot when rendered with list o
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -113,6 +116,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with child 1`] = `
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -144,6 +148,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with child className 1`]
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -175,6 +180,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with child id 1`] = `
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -208,6 +214,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with child style 1`] = `
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -240,6 +247,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with child thats disabled
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -271,6 +279,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with child thats disabled
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -303,6 +312,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with child thats selected
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -335,6 +345,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with className 1`] = `
aria-labelledby="test-ID"
aria-orientation="vertical"
class="example-class md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand All @@ -349,9 +360,11 @@ exports[`<RadioGroup /> snapshot should match snapshot with className 1`] = `
exports[`<RadioGroup /> snapshot should match snapshot with description 1`] = `
<DocumentFragment>
<div
aria-describedby="radio-group-description-example-id"
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="example-id"
role="radiogroup"
style="color: pink;"
>
Expand All @@ -363,6 +376,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with description 1`] = `
<small
class="md-text-wrapper"
data-type="body-secondary"
id="radio-group-description-example-id"
>
The radio group description
</small>
Expand Down Expand Up @@ -394,6 +408,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with multiple children 1`
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -454,6 +469,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with multiple children wi
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -513,6 +529,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with multiple children wi
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -572,6 +589,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with multiple children wi
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
>
<span
Expand Down Expand Up @@ -632,6 +650,7 @@ exports[`<RadioGroup /> snapshot should match snapshot with style 1`] = `
aria-labelledby="test-ID"
aria-orientation="vertical"
class="md-radio-group"
id="1"
role="radiogroup"
style="color: pink;"
>
Expand Down
2 changes: 2 additions & 0 deletions src/components/RadioSimpleGroup/RadioSimpleGroup.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ Example.args = {
),
label: <div style={{padding: '16px 0'}}>Select your favorite color</div>,
description: <div style={{padding: '16px 0'}}>Only choose one color</div>,
id: 'select-color-radio-simple-group',
};

const Layout = MultiTemplate<RadioSimpleGroupProps>(RadioSimpleGroup).bind({});
Expand Down Expand Up @@ -149,6 +150,7 @@ Layout.parameters = {
),
label: <div style={{padding: '16px 0'}}>Layout</div>,
description: <div style={{padding: '16px 0'}}>Please choose your favorite layout</div>,
id: 'select-layout-radio-simple-group',
},
],
};
Expand Down
8 changes: 6 additions & 2 deletions src/components/RadioSimpleGroup/RadioSimpleGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { FC } from 'react';
import classnames from 'classnames';
import { v4 as uuidV4 } from 'uuid';
import { useRadioGroup } from '@react-aria/radio';
import { useRadioGroupState } from '@react-stately/radio';

Expand All @@ -17,17 +18,20 @@ const RadioSimpleGroup: FC<RadioSimpleGroupProps> = (props: RadioSimpleGroupProp

const state = useRadioGroupState(props);
const { radioGroupProps, labelProps } = useRadioGroup(props, state);
const radioSimpleGroupId = id || uuidV4();
const descriptionId = description ? `radio-simple-group-description-${radioSimpleGroupId}` : undefined;

return (
<div
{...radioGroupProps}
className={classnames(className, STYLE.wrapper)}
data-disabled={state.isDisabled}
id={id}
id={radioSimpleGroupId}
style={style}
aria-describedby={descriptionId}
>
{label && <span {...labelProps}>{label}</span>}
{description}
{description && <span id={descriptionId}>{description}</span>}
<RadioSimpleGroupContext.Provider value={state}>{children}</RadioSimpleGroupContext.Provider>
</div>
);
Expand Down
17 changes: 17 additions & 0 deletions src/components/RadioSimpleGroup/RadioSimpleGroup.unit.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import RadioSimple from '../RadioSimple';
import Text from '../Text';
import Icon from '../Icon';

jest.mock('uuid', () => {
return {
v4: () => '1',
};
});

describe('<RadioSimpleGroup />', () => {
const children = [
<RadioSimple value="red" key="0">
Expand Down Expand Up @@ -83,6 +89,7 @@ describe('<RadioSimpleGroup />', () => {
<RadioSimpleGroup
children={children}
description={description}
id='example-id'
/>
);

Expand Down Expand Up @@ -140,6 +147,16 @@ describe('<RadioSimpleGroup />', () => {
expect(radioGroup).toHaveClass(STYLE.wrapper);
});

it('should have provided aria-describedby when description is provided', () => {
expect.assertions(1);

render(<RadioSimpleGroup children={children} description={description} id='example-id' />);

const radioGroup = screen.getByRole('radiogroup');

expect(radioGroup).toHaveAttribute('aria-describedby', 'radio-simple-group-description-example-id');
});

it('should have provided class when className is provided', () => {
expect.assertions(1);

Expand Down
Loading

0 comments on commit 38da3c8

Please sign in to comment.