Skip to content

Adds CheckboxGroup and RadioGroup components to replace ChoiceFieldset #1862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Feb 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
03c1b09
adds ChoiceGroup components and Storybook stories
mperrotti Feb 10, 2022
b7c17dc
removes unnecessary code from ChoiceGroup
mperrotti Feb 10, 2022
cd22868
adds tests and fixes issues discovered during testing
mperrotti Feb 11, 2022
baab26b
adds sx prop and standard component tests
mperrotti Feb 11, 2022
7e11b66
converts stories to fixtures and examples, adds axe violation tests
mperrotti Feb 11, 2022
de6879e
marks ChoiceFieldset as deprecated
mperrotti Feb 11, 2022
95378dc
adds ChoiceGroup docs
mperrotti Feb 11, 2022
877a579
updates snapshots
mperrotti Feb 11, 2022
c8f107e
Merge branch 'main' of github.com:primer/react into mp/choicefieldset…
mperrotti Feb 11, 2022
9f58c96
adds changeset
mperrotti Feb 11, 2022
66503cd
fixes tests I accidentally broke
mperrotti Feb 11, 2022
c46de0e
Merge branch 'main' into mp/choicefieldset-replacement
mperrotti Feb 16, 2022
2909cfc
addresses PR feedback
mperrotti Feb 17, 2022
f5a8e3d
Merge branch 'main' of github.com:primer/react into mp/choicefieldset…
mperrotti Feb 17, 2022
bf67865
Merge branch 'mp/choicefieldset-replacement' of github.com:primer/rea…
mperrotti Feb 17, 2022
c1b58bb
cleanup
mperrotti Feb 17, 2022
e8191f6
WIP - splitting CheckboxGroup and RadioGroup
mperrotti Feb 17, 2022
83e94cd
Merge branch 'main' into mp/choicefieldset-replacement
mperrotti Feb 22, 2022
da0e6de
cleans up, adds RadioGroup component
mperrotti Feb 22, 2022
d64f437
adds stories for CheckboxGroup and RadioGroup
mperrotti Feb 22, 2022
7039c8b
adds and updates tests
mperrotti Feb 22, 2022
c108f69
ts fixes, rm ChoiceGroup stories
mperrotti Feb 22, 2022
38f3209
renames ChoiceGroup to CheckboxOrRadioGroup
mperrotti Feb 22, 2022
c291075
updates docs, handles pre-selected radios and/or checkboxes
mperrotti Feb 23, 2022
c9632a2
updates snapshots
mperrotti Feb 23, 2022
e04694d
Merge branch 'main' of github.com:primer/react into mp/choicefieldset…
mperrotti Feb 23, 2022
75ffb78
cleans up, fixes broken tests
mperrotti Feb 23, 2022
331f24e
Merge branch 'mp/choicefieldset-replacement' of github.com:primer/rea…
mperrotti Feb 23, 2022
9001f15
Merge branch 'main' into mp/choicefieldset-replacement
mperrotti Feb 23, 2022
43d49bd
Merge branch 'main' into mp/choicefieldset-replacement
mperrotti Feb 24, 2022
6e0c553
Merge branch 'main' into mp/choicefieldset-replacement
mperrotti Feb 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/hip-buses-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': minor
---

Adds CheckboxGroup and RadioGroup components to replace the ChoiceFieldset component
317 changes: 317 additions & 0 deletions docs/content/CheckboxGroup.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
---
title: CheckboxGroup
description: A `CheckboxGroup` is used to render a set of checkboxes to let users select one or more options
status: Alpha
source: https://github.com/primer/react/blob/main/src/CheckboxGroup/CheckboxGroup.tsx
storybook: '/react/storybook/?path=/story/forms-checkboxgroup-examples--basic'
---

import {CheckboxGroup, Checkbox, Box} from '@primer/components'
import {CheckIcon, XIcon, AlertIcon} from '@primer/octicons-react'
import {ComponentChecklist} from '../src/component-checklist'

## Examples

### Basic

```jsx live
<Box display="grid" sx={{gap: 3}}>
<CheckboxGroup>
<CheckboxGroup.Label>Choices</CheckboxGroup.Label>
<FormControl>
<Checkbox value="one" />
<FormControl.Label>Choice one</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="two" />
<FormControl.Label>Choice two</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="three" />
<FormControl.Label>Choice three</FormControl.Label>
</FormControl>
</CheckboxGroup>
</Box>
```

### Using onChange handlers

```javascript live noinline
const WithOnChangeHandlers = () => {
const [selectedCheckboxValues, setSelectedCheckboxValues] = React.useState(['one', 'two'])
const [lastSelectedCheckboxValue, setLastSelectedCheckboxValue] = React.useState()

const handleCheckboxGroupChange = (selectedValues, e) => {
setSelectedCheckboxValues(selectedValues)
setLastSelectedCheckboxValue(e.currentTarget.value)
}

const handleChoiceOneChange = e => {
alert('Choice one has its own handler')
}

return (
<Box display="grid" sx={{gap: 1}}>
<CheckboxGroup onChange={handleCheckboxGroupChange}>
<CheckboxGroup.Label>Choices</CheckboxGroup.Label>
<FormControl>
<Checkbox value="one" defaultChecked onChange={handleChoiceOneChange} />
<FormControl.Label>Choice one</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="two" defaultChecked />
<FormControl.Label>Choice two</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="three" />
<FormControl.Label>Choice three</FormControl.Label>
</FormControl>
</CheckboxGroup>

{Boolean(selectedCheckboxValues.length) && (
<div>The selected checkbox values are {selectedCheckboxValues.join(', ')}</div>
)}
{Boolean(lastSelectedCheckboxValue) && <div>The last affected checkbox value is {lastSelectedCheckboxValue}</div>}
</Box>
)
}

render(<WithOnChangeHandlers />)
```

### Disabled

```jsx live
<CheckboxGroup disabled>
<CheckboxGroup.Label>Choices</CheckboxGroup.Label>
<FormControl>
<Checkbox value="one" />
<FormControl.Label>Choice one</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="two" />
<FormControl.Label>Choice two</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="three" />
<FormControl.Label>Choice three</FormControl.Label>
</FormControl>
</CheckboxGroup>
```

### Required

```jsx live
<CheckboxGroup required>
<CheckboxGroup.Label>Choices</CheckboxGroup.Label>
<FormControl>
<Checkbox value="one" />
<FormControl.Label>Choice one</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="two" />
<FormControl.Label>Choice two</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="three" />
<FormControl.Label>Choice three</FormControl.Label>
</FormControl>
</CheckboxGroup>
```

### With validation

```jsx live
<CheckboxGroup>
<CheckboxGroup.Label>Choices</CheckboxGroup.Label>
<FormControl>
<Checkbox value="one" />
<FormControl.Label>Choice one</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="two" />
<FormControl.Label>Choice two</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="three" />
<FormControl.Label>Choice three</FormControl.Label>
</FormControl>
<CheckboxGroup.Validation variant="error">Your choices are wrong</CheckboxGroup.Validation>
</CheckboxGroup>
```

### With caption

```jsx live
<CheckboxGroup>
<CheckboxGroup.Label>Choices</CheckboxGroup.Label>
<CheckboxGroup.Caption>You can pick any or all of these choices</CheckboxGroup.Caption>
<FormControl>
<Checkbox value="one" />
<FormControl.Label>Choice one</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="two" />
<FormControl.Label>Choice two</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="three" />
<FormControl.Label>Choice three</FormControl.Label>
</FormControl>
</CheckboxGroup>
```

### A visually hidden label

```jsx live
<CheckboxGroup>
<CheckboxGroup.Label visuallyHidden>Choices</CheckboxGroup.Label>
<FormControl>
<Checkbox value="one" />
<FormControl.Label>Choice one</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="two" />
<FormControl.Label>Choice two</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="three" />
<FormControl.Label>Choice three</FormControl.Label>
</FormControl>
</CheckboxGroup>
```

### With an external label

```jsx live
<>
<Box
id="choiceHeading"
borderBottomWidth="1px"
borderBottomStyle="solid"
borderBottomColor="border.default"
pb={2}
mb={3}
fontSize={3}
>
Choices
</Box>
<CheckboxGroup aria-labelledby="choiceHeading">
<FormControl>
<Checkbox value="one" />
<FormControl.Label>Choice one</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="two" />
<FormControl.Label>Choice two</FormControl.Label>
</FormControl>
<FormControl>
<Checkbox value="three" />
<FormControl.Label>Choice three</FormControl.Label>
</FormControl>
</CheckboxGroup>
</>
```

## Props

### CheckboxGroup

<PropsTable>
<PropsTableRow
name="aria-labelledby"
type="string"
description="Used when associating the input group with a label other than CheckboxGroup.Label"
/>
<PropsTableRow
name="children"
type="CheckboxGroup.Label | CheckboxGroup.Caption | CheckboxGroup.Validation | FormControl"
required
/>
<PropsTableRow
name="disabled"
type="boolean"
defaultValue="false"
description="Whether the input group allows user input"
/>
<PropsTableRow
name="id"
type="string"
defaultValue="a generated string"
description={
<span>
The unique identifier for this input group. Used to associate the label, validation text, and caption text.{' '}
<br /> You may want a custom ID to make it easier to select elements in integration tests.
</span>
}
/>
<PropsTableRow
name="onChange"
type="(selected: string[], e?: ChangeEvent<HTMLInputElement>) => void"
description="An onChange handler that gets called when the selection changes"
/>
<PropsTableRow
name="required"
type="boolean"
defaultValue="false"
description="If true, the user must make a selection before the owning form can be submitted"
/>
<PropsTableSxRow />
</PropsTable>

### CheckboxGroup.Label

A title for the set of choices. If a `CheckboxGroup.Label` is not passed as a child, you must pass the external title's ID to the `aria-describedby` prop on `CheckboxGroup`

<PropsTable>
<PropsTableRow
name="visuallyHidden"
type="boolean"
defaultValue="false"
description="If true, the fieldset legend will be visually hidden"
/>
<PropsTableSxRow />
</PropsTable>

### CheckboxGroup.Description

<PropsTable>
<PropsTableRow name="children" type="React.ReactNode" description="The caption content" />
<PropsTableSxRow />
</PropsTable>

### CheckboxGroup.Validation

If the user's selection has been flagged during validation, `CheckboxGroup.Validation` may be used to render contextual validation information to help the user complete their task

<PropsTable>
<PropsTableRow name="children" type="React.ReactNode" description="The validation message" />
<PropsTableRow
required
name="variant"
type="'error' | 'success' | 'warning'"
description="Changes the visual style to match the validation status"
/>
<PropsTableSxRow />
</PropsTable>

## Status

<ComponentChecklist
items={{
propsDocumented: true,
noUnnecessaryDeps: true,
adaptsToThemes: true,
adaptsToScreenSizes: true,
fullTestCoverage: true,
usedInProduction: false,
usageExamplesDocumented: true,
hasStorybookStories: true,
designReviewed: false,
a11yReviewed: false,
stableApi: false,
addressedApiFeedback: false,
hasDesignGuidelines: false,
hasFigmaComponent: false
}}
/>
6 changes: 5 additions & 1 deletion docs/content/ChoiceFieldset.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: ChoiceFieldset
status: Alpha
status: Deprecated
source: https://github.com/primer/react/blob/main/src/ChoiceFieldset/ChoiceFieldset.tsx
storybook: '/react/storybook/?path=/story/forms-choicefieldset--radio-group'
---
Expand All @@ -11,6 +11,10 @@ import {ComponentChecklist} from '../src/component-checklist'

A `ChoiceFieldset` is a controlled component that is used to render a related set of checkbox or radio inputs.

## Deprecation

Use [CheckboxGroup](/CheckboxGroup) or [RadioGroup](/RadioGroup) instead.

## Examples

### Basic
Expand Down
Loading