Skip to content

Commit 42a39f4

Browse files
authored
checkbox: Add unstable Provider, Trigger and BubbleInput (#3459)
1 parent e2e0559 commit 42a39f4

File tree

5 files changed

+867
-227
lines changed

5 files changed

+867
-227
lines changed

.changeset/heavy-rockets-allow.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@radix-ui/react-checkbox': minor
3+
'radix-ui': minor
4+
---
5+
6+
Add unstable `Provider`, `Trigger` and `BubbleInput` parts to Checkbox (#3459)

apps/storybook/stories/checkbox.stories.tsx

Lines changed: 195 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,199 @@
1+
/* eslint-disable react/jsx-pascal-case */
12
import * as React from 'react';
23
import { Checkbox, Label as LabelPrimitive } from 'radix-ui';
34
import styles from './checkbox.stories.module.css';
45

56
export default { title: 'Components/Checkbox' };
67

78
export const Styled = () => (
9+
<>
10+
<p>This checkbox is nested inside a label. The state is uncontrolled.</p>
11+
12+
<h1>Custom label</h1>
13+
<Label>
14+
Label{' '}
15+
<Checkbox.unstable_Provider>
16+
<Checkbox.unstable_Trigger className={styles.root}>
17+
<Checkbox.Indicator className={styles.indicator} />
18+
</Checkbox.unstable_Trigger>
19+
</Checkbox.unstable_Provider>
20+
</Label>
21+
22+
<br />
23+
<br />
24+
25+
<h1>Native label</h1>
26+
<label>
27+
Label{' '}
28+
<Checkbox.unstable_Provider>
29+
<Checkbox.unstable_Trigger className={styles.root}>
30+
<Checkbox.Indicator className={styles.indicator} />
31+
</Checkbox.unstable_Trigger>
32+
</Checkbox.unstable_Provider>
33+
</label>
34+
35+
<h1>Native label + native checkbox</h1>
36+
<label>
37+
Label <input type="checkbox" />
38+
</label>
39+
40+
<h1>Custom label + htmlFor</h1>
41+
<Label htmlFor="one">Label</Label>
42+
<Checkbox.unstable_Provider>
43+
<Checkbox.unstable_Trigger className={styles.root} id="one">
44+
<Checkbox.Indicator className={styles.indicator} />
45+
</Checkbox.unstable_Trigger>
46+
</Checkbox.unstable_Provider>
47+
48+
<br />
49+
<br />
50+
51+
<h1>Native label + htmlFor</h1>
52+
<label htmlFor="two">Label</label>
53+
<Checkbox.unstable_Provider>
54+
<Checkbox.unstable_Trigger className={styles.root} id="two">
55+
<Checkbox.Indicator className={styles.indicator} />
56+
</Checkbox.unstable_Trigger>
57+
</Checkbox.unstable_Provider>
58+
59+
<h1>Native label + native checkbox</h1>
60+
<label htmlFor="three">Label</label>
61+
<input type="checkbox" id="three" />
62+
</>
63+
);
64+
65+
export const Controlled = () => {
66+
const [checked, setChecked] = React.useState<boolean | 'indeterminate'>(true);
67+
68+
return (
69+
<>
70+
<p>This checkbox is placed adjacent to its label. The state is controlled.</p>
71+
<Label htmlFor="randBox">Label</Label>{' '}
72+
<Checkbox.unstable_Provider checked={checked} onCheckedChange={setChecked}>
73+
<Checkbox.unstable_Trigger className={styles.root} id="randBox">
74+
<Checkbox.Indicator className={styles.indicator} />
75+
</Checkbox.unstable_Trigger>
76+
</Checkbox.unstable_Provider>
77+
</>
78+
);
79+
};
80+
81+
export const Indeterminate = () => {
82+
const [checked, setChecked] = React.useState<boolean | 'indeterminate'>('indeterminate');
83+
84+
return (
85+
<>
86+
<p>
87+
<Checkbox.unstable_Provider checked={checked} onCheckedChange={setChecked}>
88+
<Checkbox.unstable_Trigger className={styles.root}>
89+
<Checkbox.Indicator className={styles.indicator} />
90+
</Checkbox.unstable_Trigger>
91+
</Checkbox.unstable_Provider>
92+
</p>
93+
94+
<button
95+
type="button"
96+
onClick={() =>
97+
setChecked((prevIsChecked) =>
98+
prevIsChecked === 'indeterminate' ? false : 'indeterminate'
99+
)
100+
}
101+
>
102+
Toggle indeterminate
103+
</button>
104+
</>
105+
);
106+
};
107+
108+
export const WithinForm = () => {
109+
const [data, setData] = React.useState({ optional: false, required: false, stopprop: false });
110+
const [checked, setChecked] = React.useState<boolean | 'indeterminate'>('indeterminate');
111+
112+
return (
113+
<form
114+
onSubmit={(event) => event.preventDefault()}
115+
onChange={(event) => {
116+
const input = event.target as HTMLInputElement;
117+
setData((prevData) => ({ ...prevData, [input.name]: input.checked }));
118+
}}
119+
>
120+
<fieldset>
121+
<legend>optional checked: {String(data.optional)}</legend>
122+
<label>
123+
<Checkbox.Root
124+
className={styles.root}
125+
name="optional"
126+
checked={checked}
127+
onCheckedChange={setChecked}
128+
>
129+
<Checkbox.Indicator className={styles.indicator} />
130+
</Checkbox.Root>{' '}
131+
with label
132+
</label>
133+
<br />
134+
<br />
135+
136+
<button
137+
type="button"
138+
onClick={() => {
139+
setChecked((v) => (v === 'indeterminate' ? false : 'indeterminate'));
140+
}}
141+
>
142+
Toggle indeterminate
143+
</button>
144+
</fieldset>
145+
146+
<br />
147+
<br />
148+
149+
<fieldset>
150+
<legend>required checked: {String(data.required)}</legend>
151+
<Checkbox.unstable_Provider name="required" required>
152+
<Checkbox.unstable_Trigger className={styles.root}>
153+
<Checkbox.Indicator className={styles.indicator} />
154+
</Checkbox.unstable_Trigger>
155+
<Checkbox.unstable_BubbleInput />
156+
</Checkbox.unstable_Provider>
157+
</fieldset>
158+
159+
<br />
160+
<br />
161+
162+
<fieldset>
163+
<legend>stop propagation checked: {String(data.stopprop)}</legend>
164+
<Checkbox.unstable_Provider name="stopprop">
165+
<Checkbox.unstable_Trigger
166+
className={styles.root}
167+
onClick={(event) => event.stopPropagation()}
168+
>
169+
<Checkbox.Indicator className={styles.indicator} />
170+
</Checkbox.unstable_Trigger>
171+
<Checkbox.unstable_BubbleInput />
172+
</Checkbox.unstable_Provider>
173+
</fieldset>
174+
175+
<br />
176+
<br />
177+
178+
<fieldset>
179+
<legend>no bubble input checked: {String(data.stopprop)}</legend>
180+
<Checkbox.unstable_Provider name="stopprop">
181+
<Checkbox.unstable_Trigger className={styles.root}>
182+
<Checkbox.Indicator className={styles.indicator} />
183+
</Checkbox.unstable_Trigger>
184+
</Checkbox.unstable_Provider>
185+
</fieldset>
186+
187+
<br />
188+
<br />
189+
190+
<button type="reset">Reset</button>
191+
<button>Submit</button>
192+
</form>
193+
);
194+
};
195+
196+
export const LegacyStyled = () => (
8197
<>
9198
<p>This checkbox is nested inside a label. The state is uncontrolled.</p>
10199

@@ -53,7 +242,7 @@ export const Styled = () => (
53242
</>
54243
);
55244

56-
export const Controlled = () => {
245+
export const LegacyControlled = () => {
57246
const [checked, setChecked] = React.useState<boolean | 'indeterminate'>(true);
58247

59248
return (
@@ -72,7 +261,7 @@ export const Controlled = () => {
72261
);
73262
};
74263

75-
export const Indeterminate = () => {
264+
export const LegacyIndeterminate = () => {
76265
const [checked, setChecked] = React.useState<boolean | 'indeterminate'>('indeterminate');
77266

78267
return (
@@ -97,7 +286,7 @@ export const Indeterminate = () => {
97286
);
98287
};
99288

100-
export const WithinForm = () => {
289+
export const LegacyWithinForm = () => {
101290
const [data, setData] = React.useState({ optional: false, required: false, stopprop: false });
102291
const [checked, setChecked] = React.useState<boolean | 'indeterminate'>('indeterminate');
103292

@@ -170,7 +359,7 @@ export const WithinForm = () => {
170359
);
171360
};
172361

173-
export const Animated = () => {
362+
export const LegacyAnimated = () => {
174363
const [checked, setChecked] = React.useState<boolean | 'indeterminate'>('indeterminate');
175364

176365
return (
@@ -195,7 +384,7 @@ export const Animated = () => {
195384
);
196385
};
197386

198-
export const Chromatic = () => (
387+
export const LegacyChromatic = () => (
199388
<>
200389
<h1>Uncontrolled</h1>
201390
<h2>Unchecked</h2>
@@ -261,6 +450,6 @@ export const Chromatic = () => (
261450
</Checkbox.Root>
262451
</>
263452
);
264-
Chromatic.parameters = { chromatic: { disable: false } };
453+
LegacyChromatic.parameters = { chromatic: { disable: false } };
265454

266455
const Label = (props: any) => <LabelPrimitive.Root {...props} className={styles.label} />;

0 commit comments

Comments
 (0)