Radio
Radio Examples
Copy-ready examples for a controlled radio group.
Controlled group (recommended)
Treat Radio as controlled by passing isChecked + onChange. This is the most reliable way to keep state in sync.
Live preview
Helper text
Basic group
import { useId, useState } from "react";
import Radio from "@/_components/radio/Radio";
export default function Example() {
const group = useId();
const [value, setValue] = useState<"a" | "b">("a");
return (
<div style={{ display: "grid", gap: 12 }}>
<Radio
nameGroup={group}
value="a"
label="Option A"
isChecked={value === "a"}
onChange={() => setValue("a")}
/>
<Radio
nameGroup={group}
value="b"
label="Option B"
isChecked={value === "b"}
onChange={() => setValue("b")}
extraTextContent="Helper text"
extraTextState="support"
/>
</div>
);
}Variants and sizes
Use variant for semantic styling and size to match density. Keep a single nameGroup so only one option is selected.
Live preview
Variant + size
import { useId, useState } from "react";
import Radio from "@/_components/radio/Radio";
export default function Example() {
const group = useId();
const [value, setValue] = useState<"primary" | "danger" | "success">("primary");
return (
<div style={{ display: "grid", gap: 12 }}>
<Radio
nameGroup={group}
value="primary"
label="Primary / small"
variant="primary"
size="small"
isChecked={value === "primary"}
onChange={() => setValue("primary")}
/>
<Radio
nameGroup={group}
value="success"
label="Success / medium"
variant="success"
size="medium"
isChecked={value === "success"}
onChange={() => setValue("success")}
/>
<Radio
nameGroup={group}
value="danger"
label="Danger / large"
variant="danger"
size="large"
isChecked={value === "danger"}
onChange={() => setValue("danger")}
/>
</div>
);
}Label position
Place the label on the left or right of the control.
Live preview
Left vs right
import { useId, useState } from "react";
import Radio from "@/_components/radio/Radio";
export default function Example() {
const group = useId();
const [value, setValue] = useState<"left" | "right">("left");
return (
<div style={{ display: "grid", gap: 12 }}>
<Radio
nameGroup={group}
value="left"
label="Label on the left"
labelPosition="left"
isChecked={value === "left"}
onChange={() => setValue("left")}
/>
<Radio
nameGroup={group}
value="right"
label="Label on the right"
labelPosition="right"
isChecked={value === "right"}
onChange={() => setValue("right")}
/>
</div>
);
}Helper text states
Use extraTextState to convey validation or guidance. Useful for forms and onboarding.
Live preview
Helper text (support)
Looks good
Something went wrong
Support / success / error
import { useId, useState } from "react";
import Radio from "@/_components/radio/Radio";
export default function Example() {
const group = useId();
const [value, setValue] = useState<"support" | "success" | "error">("support");
return (
<div style={{ display: "grid", gap: 12 }}>
<Radio
nameGroup={group}
value="support"
label="Support"
isChecked={value === "support"}
onChange={() => setValue("support")}
extraTextContent="Helper text (support)"
extraTextState="support"
/>
<Radio
nameGroup={group}
value="success"
label="Success"
isChecked={value === "success"}
onChange={() => setValue("success")}
extraTextContent="Looks good"
extraTextState="success"
/>
<Radio
nameGroup={group}
value="error"
label="Error"
isChecked={value === "error"}
onChange={() => setValue("error")}
extraTextContent="Something went wrong"
extraTextState="error"
/>
</div>
);
}Disabled and required
Use required for forms and disabled to block selection. Keep isChecked stable for disabled items.
Live preview
Disabled radios should not change state.
Required + disabled
import { useId, useState } from "react";
import Radio from "@/_components/radio/Radio";
export default function Example() {
const group = useId();
const [value, setValue] = useState<"yes" | "no">("yes");
return (
<div style={{ display: "grid", gap: 12 }}>
<Radio
nameGroup={group}
value="yes"
label="Required choice (Yes)"
required
isChecked={value === "yes"}
onChange={() => setValue("yes")}
/>
<Radio
nameGroup={group}
value="no"
label="Disabled option (No)"
disabled
isChecked={value === "no"}
onChange={() => setValue("no")}
extraTextContent="Disabled radios should not change state."
extraTextState="support"
/>
</div>
);
}String and number values
value supports string | number. Compare with the same type to avoid mismatches (e.g. 1 !== "1").
Live preview
Selected value is 1
Selected value is 1
Mixed value types
import { useId, useState } from "react";
import Radio from "@/packages/ui/src/_components/radio/Radio";
export default function Example() {
const group = useId();
const [value, setValue] = useState<string | number>(1);
return (
<div style={{ display: "grid", gap: 12 }}>
<Radio
nameGroup={group}
value={1}
label="Value: 1 (number)"
isChecked={value === 1}
onChange={() => setValue(1)}
extraTextContent={`Selected value is ${String(value)}`}
extraTextState="support"
/>
<Radio
nameGroup={group}
value="2"
label='Value: "2" (string)'
isChecked={value === "2"}
onChange={() => setValue("2")}
extraTextContent={`Selected value is ${String(value)}`}
extraTextState="support"
/>
</div>
);
}On this page
Radio Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| value | string | number | Yes | — | Value for the radio input. |
| nameGroup | string | Yes | — | Name attribute used to group multiple radios. Radios with the same nameGroup behave as a single selection group. |
| variant | "primary" | "secondary" | "tertiary" | "success" | "warning" | "danger" | "info" | No | "primary" | Visual/semantic variant (maps to cssnt-radio--* classes). |
| size | "small" | "medium" | "large" | No | "small" | Size modifier (maps to cssnt-radio--sm/md/lg). |
| label | string | No | — | Text label rendered next to the control. |
| labelPosition | "left" | "right" | No | "left" | Position of the label relative to the control. |
| required | boolean | No | false | Adds required attribute to the input and a required class to the label container. |
| isChecked | boolean | No | — | Whether the radio is checked. Recommended to always pass a boolean when controlling the selection. |
| disabled | boolean | No | false | Disables the input. |
| extraTextContent | string | No | — | Helper/extra text shown under the radio. Note: the helper element may still render even if content is empty. |
| extraTextState | "support" | "success" | "error" | No | "support" | Helper text style. |
| onChange | (...args: unknown[]) => unknown | No | — | Change handler forwarded to the native input. Use it to update external state (recommended). |
| onClick | (...args: unknown[]) => unknown | No | — | Click handler forwarded to the native input. |
Components