Skip to content

Commit

Permalink
feat: improve radio-group components a11y
Browse files Browse the repository at this point in the history
  • Loading branch information
amje committed Jun 15, 2022
1 parent 7bd43bf commit 0c438d3
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 10 deletions.
10 changes: 8 additions & 2 deletions src/components/RadioButton/RadioButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,16 @@ export const RadioButton = React.forwardRef<HTMLDivElement, RadioButtonProps>(fu
event.currentTarget.hidden = true;
}, []);

const {optionsProps} = useRadioGroup({...props, options});
const {containerProps, optionsProps} = useRadioGroup({...props, options});

return (
<div ref={ref} style={style} className={b({size, width}, className)} data-qa={qa}>
<div
{...containerProps}
ref={ref}
style={style}
className={b({size, width}, className)}
data-qa={qa}
>
<div
ref={plateRef}
className={b('plate')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ const options: RadioButtonOption[] = [
{value: 'Value 3', content: 'Value 3'},
];

const DefaultTemplate: Story<RadioButtonProps> = (args) => <RadioButton {...args} />;
const DefaultTemplate: Story<RadioButtonProps> = (args) => {
const [value, setValue] = React.useState<string>(options[0].value);
return <RadioButton {...args} value={value} onUpdate={setValue} />;
};
export const Default = DefaultTemplate.bind({});
Default.args = {
value: options[0].value,
options,
};

Expand Down
10 changes: 8 additions & 2 deletions src/components/RadioGroup/RadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,16 @@ export const RadioGroup = React.forwardRef<HTMLDivElement, RadioGroupProps>(func
}));
}

const {optionsProps} = useRadioGroup({...props, options});
const {containerProps, optionsProps} = useRadioGroup({...props, options});

return (
<div ref={ref} style={style} className={b({size, direction}, className)} data-qa={qa}>
<div
{...containerProps}
ref={ref}
style={style}
className={b({size, direction}, className)}
data-qa={qa}
>
{optionsProps.map((optionProps) => (
<Radio
{...optionProps}
Expand Down
6 changes: 4 additions & 2 deletions src/components/RadioGroup/__stories__/RadioGroup.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ const options: RadioGroupOption[] = [
{value: 'Value 3', content: 'Value 3'},
];

const DefaultTemplate: Story<RadioGroupProps> = (args) => <RadioGroup {...args} />;
const DefaultTemplate: Story<RadioGroupProps> = (args) => {
const [value, setValue] = React.useState<string>(options[0].value);
return <RadioGroup {...args} value={value} onUpdate={setValue} />;
};
export const Default = DefaultTemplate.bind({});
Default.args = {
value: options[0].value,
options,
};

Expand Down
4 changes: 4 additions & 0 deletions src/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ export interface ControlGroupProps {
defaultValue?: string;
onUpdate?: (value: string) => void;
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
onFocus?: (event: React.FocusEvent<HTMLInputElement>) => void;
onBlur?: (event: React.FocusEvent<HTMLInputElement>) => void;
disabled?: boolean;
options?: ControlGroupOption[];
'aria-label'?: string;
'aria-labelledby'?: string;
}
22 changes: 20 additions & 2 deletions src/components/utils/useRadioGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ import {ControlGroupProps} from '../types';
import {useUniqId} from './useUniqId';

export function useRadioGroup(props: ControlGroupProps) {
const {name, value, defaultValue, options = [], disabled, onUpdate, onChange} = props;
const {
name,
value,
defaultValue,
options = [],
disabled,
onUpdate,
onChange,
onFocus,
onBlur,
} = props;

const controlId = useUniqId();
const [valueState, setValueState] = React.useState(
Expand All @@ -28,14 +38,22 @@ export function useRadioGroup(props: ControlGroupProps) {
[isControlled, onUpdate, onChange],
);

const containerProps = {
role: 'radiogroup',
'aria-label': props['aria-label'],
'aria-labelledby': props['aria-labelledby'],
};

const optionsProps = options.map((option) => ({
name: name || controlId,
value: String(option.value),
content: option.content,
checked: currentValue === String(option.value),
disabled: disabled || option.disabled,
onChange: handleChange,
onFocus: onFocus,
onBlur: onBlur,
}));

return {optionsProps};
return {containerProps, optionsProps};
}

0 comments on commit 0c438d3

Please sign in to comment.