radio_button_checked

Radio

Single-choice selection within a group.

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

Radio — Props
PropTypeRequiredDefaultDescription
valuestring | numberYesValue for the radio input.
nameGroupstringYesName 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).
labelstringNoText label rendered next to the control.
labelPosition"left" | "right"No"left"Position of the label relative to the control.
requiredbooleanNofalseAdds required attribute to the input and a required class to the label container.
isCheckedbooleanNoWhether the radio is checked. Recommended to always pass a boolean when controlling the selection.
disabledbooleanNofalseDisables the input.
extraTextContentstringNoHelper/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[]) => unknownNoChange handler forwarded to the native input. Use it to update external state (recommended).
onClick(...args: unknown[]) => unknownNoClick handler forwarded to the native input.