Skip to content

Commit

Permalink
feat: abstract Radio and RadioGroup
Browse files Browse the repository at this point in the history
  • Loading branch information
jordankoschei-okta committed Jan 19, 2023
1 parent e99b142 commit 6b34afa
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 205 deletions.
35 changes: 31 additions & 4 deletions packages/odyssey-react-mui/src/RadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,40 @@
* See the License for the specific language governing permissions and limitations under the License.
*/

import { Radio } from "./";
import { FormControl, FormLabel, FormHelperText, visuallyHidden } from "./";
import { RadioGroup as MuiRadioGroup } from "@mui/material";

export interface RadioGroupProps {
value: string;
label: string;
hint?: string | undefined;
disabled?: boolean | undefined;
invalid?: boolean | undefined;
error?: any | undefined;
children: any;
}

export const RadioGroup = ({ value, label }: RadioGroupProps) => (
<Radio value={value} label={label} />
export const RadioGroup = ({
label,
hint,
disabled,
invalid,
error,
children,
}: RadioGroupProps) => (
<FormControl component="fieldset" disabled={disabled} error={invalid}>
<FormLabel component="legend">{label}</FormLabel>
{hint && <FormHelperText id="radio-hint">{hint}</FormHelperText>}
<MuiRadioGroup
defaultValue="Lightspeed"
name="radio-buttons-group"
aria-describedby="radio-hint radio-error"
>
{children}
</MuiRadioGroup>
{error && (
<FormHelperText id="radio-error" error>
<span style={visuallyHidden}>Error:</span> {error}
</FormHelperText>
)}
</FormControl>
);
Original file line number Diff line number Diff line change
Expand Up @@ -6,81 +6,6 @@ import { ArgsTable, Canvas, Meta, Story } from "@storybook/addon-docs";

Use radio buttons when a user must make a single selection from a list of two or more options that are mutually exclusive.

## About

Radio buttons are wrapped into a radio group so we can visually present groups of options as distinct and separate from other possible groups on the same page.

### When to use

#### Radio group vs Checkbox

Radio buttons allow the user to select 1 option. Checkboxes, in contrast, are independent of all the other checkboxes and multiple options can be selected at the same time.

#### Radio group vs Select

Consider how you wish to present your list of options to the user. A radio group will display all possible options and make it easy to compare them without the need to first interact with the component, lowering the cognitive load for users.

## Examples

### Default

<Canvas>
<Story id="mui-components-forms-radio--default" />
</Canvas>

### Hint text

The hint text is placed in between the label and the radio buttons.

<Canvas>
<Story id="mui-components-forms-radio--hint" />
</Canvas>

### Disabled

Disabled inputs block any possible user interaction and cannot be focused.

<Canvas>
<Story id="mui-components-forms-radio--disabled" />
</Canvas>

### Invalid

Validation should happen on the group and not individually on each item.

<Canvas>
<Story id="mui-components-forms-radio--invalid" />
</Canvas>

## Anatomy

### Label

The label helps the user understand the group of options provided and in making a selection.

### Radio button input and label

Radio buttons make up the list of available options within a group.<br/>
The list is laid out vertically with one choice per line and by default one of the options is selected.<br/>
If users need to withhold an answer you should provide a neutral option for this.

### Hint text (optional)

This is an optional property that includes in-context descriptions to clarify the grouping or explain the set of options.<br/>
Hints should not include long-form content or rich text as it visually separates the intended label from the input area.

## Behaviors

### States

A radio button has 2 states: Selected and Unselected.<br/>
By default one of the options within the list should be selected. Once another option is triggered the previous selection will be deselected.<br/>
On top of the previous two states, radio buttons can also exist in all the other states needed for form inputs: `focus`, `disabled`, and `invalid`.

### Interactions

A radio button can be selected from either the radio input or the radio label, this provides a better affordance for the user.

## References and additional reading material

- Jakob Nielsen (2004, September 26) [Checkboxes vs. Radio Buttons](https://www.nngroup.com/articles/checkboxes-vs-radio-buttons/) - Nielsen Norman Group
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,7 @@
*/

import { Story } from "@storybook/react";
import {
FormControl,
FormControlLabel,
FormHelperText,
FormLabel,
Radio,
RadioGroup,
visuallyHidden,
} from "@okta/odyssey-react-mui";
import { Radio } from "@okta/odyssey-react-mui";
import { MuiThemeDecorator } from "../../../../.storybook/components";

import RadioMdx from "./Radio.mdx";
Expand All @@ -33,86 +25,21 @@ export default {
},
},
argTypes: {
disabled: {
control: "boolean",
defaultValue: false,
},
error: {
control: "text",
defaultValue: null,
},
hint: {
value: {
control: "text",
defaultValue: null,
},
invalid: {
control: "boolean",
defaultValue: false,
defaultValue: "Value",
},
label: {
control: "text",
defaultValue: "Speed",
defaultValue: "Label",
},
},
decorators: [MuiThemeDecorator],
};

const DefaultTemplate: Story = (args) => {
return (
<FormControl
component="fieldset"
disabled={args.disabled}
error={args.invalid}
>
<FormLabel component="legend">{args.label}</FormLabel>
{args.hint && (
<FormHelperText id="radio-hint">{args.hint}</FormHelperText>
)}
<RadioGroup
defaultValue="Lightspeed"
name="radio-buttons-group"
aria-describedby="radio-hint radio-error"
>
<FormControlLabel
value="Lightspeed"
control={<Radio />}
label="Lightspeed"
/>
<FormControlLabel
value="Warp speed"
control={<Radio />}
label="Warp speed"
/>
<FormControlLabel
value="Ludicrous speed"
control={<Radio />}
label="Ludicrous speed"
/>
</RadioGroup>
{args.error && (
<FormHelperText id="radio-error" error>
<span style={visuallyHidden}>Error:</span> {args.error}
</FormHelperText>
)}
</FormControl>
);
return <Radio value={args.value} label={args.label} />;
};

export const Default = DefaultTemplate.bind({});
Default.args = {};

export const Hint = DefaultTemplate.bind({});
Hint.args = {
hint: "Select the speed at which you wish to travel.",
};

export const Disabled = DefaultTemplate.bind({});
Disabled.args = {
disabled: true,
};

export const Invalid = DefaultTemplate.bind({});
Invalid.args = {
invalid: true,
error: "This field is required.",
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ArgsTable, Canvas, Meta, Story } from "@storybook/addon-docs";

<Meta anchor />

# Radio
# RadioGroup

Use radio buttons when a user must make a single selection from a list of two or more options that are mutually exclusive.

Expand All @@ -25,31 +25,31 @@ Consider how you wish to present your list of options to the user. A radio group
### Default

<Canvas>
<Story id="mui-components-forms-radio--default" />
<Story id="mui-components-forms-radiogroup--default" />
</Canvas>

### Hint text

The hint text is placed in between the label and the radio buttons.

<Canvas>
<Story id="mui-components-forms-radio--hint" />
<Story id="mui-components-forms-radiogroup--hint" />
</Canvas>

### Disabled

Disabled inputs block any possible user interaction and cannot be focused.

<Canvas>
<Story id="mui-components-forms-radio--disabled" />
<Story id="mui-components-forms-radiogroup--disabled" />
</Canvas>

### Invalid

Validation should happen on the group and not individually on each item.

<Canvas>
<Story id="mui-components-forms-radio--invalid" />
<Story id="mui-components-forms-radiogroup--invalid" />
</Canvas>

## Anatomy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,7 @@
*/

import { Story } from "@storybook/react";
import {
FormControl,
FormControlLabel,
FormHelperText,
FormLabel,
Radio,
RadioGroup,
visuallyHidden,
} from "@okta/odyssey-react-mui";
import { Radio, RadioGroup } from "@okta/odyssey-react-mui";
import { MuiThemeDecorator } from "../../../../.storybook/components";

import RadioGroupMdx from "./RadioGroup.mdx";
Expand Down Expand Up @@ -59,42 +51,17 @@ export default {

const DefaultTemplate: Story = (args) => {
return (
<FormControl
component="fieldset"
<RadioGroup
disabled={args.disabled}
error={args.invalid}
invalid={args.invalid}
error={args.error}
label={args.label}
hint={args.hint}
>
<FormLabel component="legend">{args.label}</FormLabel>
{args.hint && (
<FormHelperText id="radio-hint">{args.hint}</FormHelperText>
)}
<RadioGroup
defaultValue="Lightspeed"
name="radio-buttons-group"
aria-describedby="radio-hint radio-error"
>
<FormControlLabel
value="Lightspeed"
control={<Radio />}
label="Lightspeed"
/>
<FormControlLabel
value="Warp speed"
control={<Radio />}
label="Warp speed"
/>
<FormControlLabel
value="Ludicrous speed"
control={<Radio />}
label="Ludicrous speed"
/>
</RadioGroup>
{args.error && (
<FormHelperText id="radio-error" error>
<span style={visuallyHidden}>Error:</span> {args.error}
</FormHelperText>
)}
</FormControl>
<Radio value="lightspeed" label="Lightspeed" />
<Radio value="Warp Speed" label="Warp Speed" />
<Radio value="Ludicrous Speed" label="Ludicrous Speed" />
</RadioGroup>
);
};

Expand Down

0 comments on commit 6b34afa

Please sign in to comment.