Skip to content

Commit bc1473f

Browse files
feat(CheckBox, Radio, Switch): add labelPosition prop (#4898)
* feat(CheckBox,Radio,Switch): add `labelPosition` prop feat(CheckBox,Radio,Switch): add `labelPosition` prop * fix: keep default label position top to avoid visual breaking changes and fix label hover style --------- Co-authored-by: francisco-guilherme <[email protected]>
1 parent a4942d4 commit bc1473f

File tree

15 files changed

+228
-73
lines changed

15 files changed

+228
-73
lines changed

apps/docs/src/app/examples/switches/CustomSwitch.tsx

Lines changed: 0 additions & 26 deletions
This file was deleted.

apps/docs/src/app/examples/switches/page.mdx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ title: "Switches"
33
---
44

55
import { CodeBlock } from "../../../components/code/CodeBlock";
6-
import CustomSwitch from "./CustomSwitch?raw";
76
import SwitchWithIcon from "./SwitchWithIcon?raw";
87

98
### Switch Components
@@ -12,11 +11,6 @@ Explore different switch types and features.
1211

1312
<div className="overflow-hidden mt-20">
1413
<div className="w-101% grid divide-border [grid-template-columns:repeat(auto-fit,minmax(360px,1fr))] -mt-px -mb-px auto-rows-min [&>*]:min-h-[200px]">
15-
<CodeBlock
16-
code={{ main: CustomSwitch }}
17-
layout="popup"
18-
title="Custom Switch"
19-
/>
2014
<CodeBlock
2115
code={{ main: SwitchWithIcon }}
2216
layout="popup"

apps/docs/src/content/components/checkbox.mdx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ You can use the [`color`](/docs/styling#color-prop) prop to style the color of t
3737
</div>
3838
```
3939

40+
### Label position
41+
42+
Use the `labelPosition` prop to change the position of the label.
43+
44+
```tsx live
45+
<div className="flex flex-col gap-sm">
46+
<HvCheckBox label="Label on the left" labelPosition="left" />
47+
<HvCheckBox label="Label on the right" labelPosition="right" />
48+
</div>
49+
```
50+
4051
### Controlled
4152

4253
You can share state control from a parent component. Clicking **Checkbox 1** has no effect, while clicking **Checkbox 2** updates the state and toggles both checkboxes.

apps/docs/src/content/components/radio.mdx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ You can use the [`color`](/docs/styling#color-prop) prop to style the color of t
3636
</div>
3737
```
3838

39+
### Label position
40+
41+
Use the `labelPosition` prop to change the position of the label.
42+
43+
```tsx live
44+
<div className="flex flex-col gap-sm">
45+
<HvRadio label="Label on the left" labelPosition="left" />
46+
<HvRadio label="Label on the right" labelPosition="right" />
47+
</div>
48+
```
49+
3950
### Controlled
4051

4152
Controlled radio button. Clicking the Radio button 1 does nothing, while clicking Radio button 2 changes both inputs.

apps/docs/src/content/components/switch.mdx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@ export default function Demo() {
4646
}
4747
```
4848

49+
### Label position
50+
51+
Use the `labelPosition` prop to change the position of the label.
52+
53+
```tsx live
54+
<div className="flex flex-col gap-sm">
55+
<HvSwitch label="Label on the left" labelPosition="left" />
56+
<HvSwitch label="Label on the right" labelPosition="right" />
57+
</div>
58+
```
59+
4960
### Custom colors
5061

5162
You can use the [`color`](/docs/styling#color-prop) prop to style the color of the switch.

packages/core/src/CheckBox/CheckBox.stories.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ export const Test: StoryObj<HvCheckBoxProps> = {
6868
indeterminate
6969
label="Checkbox 3"
7070
/>
71+
<HvCheckBox label="Left" labelPosition="left" />
72+
<HvCheckBox label="Right" labelPosition="right" defaultChecked />
7173
<div>
7274
<HvCheckBox aria-label="Checkbox" />
7375
<HvCheckBox defaultChecked aria-label="Checkbox" />

packages/core/src/CheckBox/CheckBox.styles.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ export const { staticClasses, useClasses } = createClasses("HvCheckBox", {
1818
":where(:has($label)) $checkbox": {
1919
borderRadius: "inherit",
2020
},
21+
"&$left": {
22+
flexDirection: "row-reverse",
23+
justifyContent: "flex-end",
24+
},
25+
"&$right": {
26+
flexDirection: "row",
27+
},
2128
},
2229
invalidContainer: {},
2330
disabled: {
@@ -32,13 +39,21 @@ export const { staticClasses, useClasses } = createClasses("HvCheckBox", {
3239
invalidCheckbox: {},
3340
label: {
3441
verticalAlign: "middle",
35-
paddingRight: theme.space.xs,
3642
...theme.typography.body,
3743
cursor: "pointer",
3844
lineHeight: "32px",
39-
width: "100%",
4045
},
4146
checked: {},
4247
indeterminate: {},
4348
semantic: {},
49+
left: {
50+
"& .HvCheckBox-label": {
51+
paddingLeft: theme.space.xs,
52+
},
53+
},
54+
right: {
55+
"& .HvCheckBox-label": {
56+
paddingRight: theme.space.xs,
57+
},
58+
},
4459
});

packages/core/src/CheckBox/CheckBox.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ export interface HvCheckBoxProps extends Omit<HvBaseCheckBoxProps, "classes"> {
4949
* Defaults to "Required" when the status is uncontrolled and no `aria-errormessage` is provided.
5050
*/
5151
statusMessage?: React.ReactNode;
52+
/**
53+
* The position of the label relative to the control.
54+
*/
55+
labelPosition?: "left" | "right";
5256
/**
5357
* A Jss Object used to override or extend the styles applied to the checkbox.
5458
*/
@@ -72,6 +76,7 @@ export const HvCheckBox = forwardRef<HTMLButtonElement, HvCheckBoxProps>(
7276
statusMessage,
7377
label,
7478
labelProps,
79+
labelPosition = "right",
7580
inputProps,
7681
value = "on",
7782
required,
@@ -220,7 +225,7 @@ export const HvCheckBox = forwardRef<HTMLButtonElement, HvCheckBoxProps>(
220225
>
221226
{hasLabel ? (
222227
<div
223-
className={cx(classes.container, {
228+
className={cx(classes.container, classes[labelPosition], {
224229
[classes.invalidContainer]: isStateInvalid,
225230
[classes.disabled]: disabled,
226231
})}

packages/core/src/Radio/Radio.stories.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ export const Test: StoryObj<HvRadioProps> = {
8383
<HvRadio defaultChecked disabled aria-label="radio" />
8484
<HvRadio color="warning" aria-label="radio" />
8585
<HvRadio defaultChecked color="warning" aria-label="radio" />
86+
<HvRadio label="Left" labelPosition="left" />
87+
<HvRadio label="Right" labelPosition="right" defaultChecked />
8688
</>
8789
),
8890
};

packages/core/src/Radio/Radio.styles.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ export const { staticClasses, useClasses } = createClasses("HvRadio", {
1818
":where(:has($label)) $radio": {
1919
borderRadius: "inherit",
2020
},
21+
"&$left": {
22+
flexDirection: "row-reverse",
23+
justifyContent: "flex-end",
24+
},
25+
"&$right": {
26+
flexDirection: "row",
27+
},
2128
},
2229
invalidContainer: {},
2330
disabled: {
@@ -32,12 +39,20 @@ export const { staticClasses, useClasses } = createClasses("HvRadio", {
3239
invalidRadio: {},
3340
label: {
3441
verticalAlign: "middle",
35-
paddingRight: theme.space.xs,
3642
...theme.typography.body,
3743
cursor: "pointer",
3844
lineHeight: "32px",
39-
width: "100%",
4045
},
4146
checked: {},
4247
semantic: {},
48+
left: {
49+
"& .HvRadio-label": {
50+
paddingLeft: theme.space.xs,
51+
},
52+
},
53+
right: {
54+
"& .HvRadio-label": {
55+
paddingRight: theme.space.xs,
56+
},
57+
},
4358
});

0 commit comments

Comments
 (0)