Propel

Radio

Lets a user pick one option from a set of mutually exclusive choices.

Show code
import { Field, FieldLabel } from "@makeplane/propel/components/field";
import { RadioGroup } from "@makeplane/propel/components/radio";
import { RadioGroupFieldOption } from "@makeplane/propel/components/radio-group-field";

export default function BasicDemo() {
  return (
    <Field name="priority">
      <FieldLabel size="lg" inset={false}>
        Priority
      </FieldLabel>
      <RadioGroup density="comfortable" defaultValue="low">
        <RadioGroupFieldOption size="lg" value="low" label="Low" />
        <RadioGroupFieldOption size="lg" value="medium" label="Medium" />
        <RadioGroupFieldOption size="lg" value="high" label="High" />
      </RadioGroup>
    </Field>
  );
}

Installation

import { Radio, RadioGroup } from "@makeplane/propel/components/radio";
import { RadioGroupFieldOption } from "@makeplane/propel/components/radio-group-field";

Usage

import { Field, FieldLabel } from "@makeplane/propel/components/field";
import { RadioGroup } from "@makeplane/propel/components/radio";
import { RadioGroupFieldOption } from "@makeplane/propel/components/radio-group-field";

export default function BasicDemo() {
  return (
    <Field name="priority">
      <FieldLabel size="lg" inset={false}>
        Priority
      </FieldLabel>
      <RadioGroup density="comfortable" defaultValue="low">
        <RadioGroupFieldOption size="lg" value="low" label="Low" />
        <RadioGroupFieldOption size="lg" value="medium" label="Medium" />
        <RadioGroupFieldOption size="lg" value="high" label="High" />
      </RadioGroup>
    </Field>
  );
}

Examples

Bare radios

Drop to the bare Radio when you compose your own rows; give each option an accessible name with aria-label. This names the control for assistive tech only — there’s no visible label text, so prefer RadioGroupFieldOption (which renders a real, visible label) whenever the row has room for one.

Show code
import { Radio, RadioGroup } from "@makeplane/propel/components/radio";

export default function BareRadiosDemo() {
  return (
    <RadioGroup density="comfortable" defaultValue="low" aria-label="Priority">
      <Radio value="low" aria-label="Low" />
      <Radio value="medium" aria-label="Medium" />
      <Radio value="high" aria-label="High" />
    </RadioGroup>
  );
}

Field composition

The ready-made RadioGroupField owns the legend, options, and helper text, so the group serializes under its name with no extra wiring.

Priority

Only one priority can be active.

Show code
import {
  RadioGroupField,
  RadioGroupFieldOption,
} from "@makeplane/propel/components/radio-group-field";

export default function FieldCompositionDemo() {
  return (
    <RadioGroupField
      name="priority"
      label="Priority"
      size="lg"
      density="comfortable"
      defaultValue="low"
      hint="Only one priority can be active."
    >
      <RadioGroupFieldOption value="low" label="Low" />
      <RadioGroupFieldOption value="medium" label="Medium" />
      <RadioGroupFieldOption value="high" label="High" />
    </RadioGroupField>
  );
}

Density

density sets the row spacing: comfortable (8px gap) or compact (flush rows, e.g. a settings panel where options read like menu items).

Comfortable density
Compact density
Show code
import {
  RadioGroupField,
  RadioGroupFieldOption,
} from "@makeplane/propel/components/radio-group-field";

export default function DensityDemo() {
  return (
    <div className="flex flex-wrap items-start gap-10">
      <RadioGroupField
        name="comfortableDensity"
        label="Comfortable density"
        size="lg"
        density="comfortable"
        defaultValue="low"
      >
        <RadioGroupFieldOption value="low" label="Comfortable" />
        <RadioGroupFieldOption value="medium" label="8px gap" />
      </RadioGroupField>
      <RadioGroupField
        name="compactDensity"
        label="Compact density"
        size="lg"
        density="compact"
        defaultValue="low"
      >
        <RadioGroupFieldOption value="low" label="Compact" />
        <RadioGroupFieldOption value="medium" label="Flush rows" />
      </RadioGroupField>
    </div>
  );
}

With description

Each option can carry supporting text, announced as the radio’s description.

Project visibility

Only invited members can view this project.

Everyone in the workspace can find and open it.

Anyone with the link can view the project.

Show code
import {
  RadioGroupField,
  RadioGroupFieldOption,
} from "@makeplane/propel/components/radio-group-field";

export default function WithDescriptionDemo() {
  return (
    <RadioGroupField
      name="visibility"
      label="Project visibility"
      size="lg"
      density="comfortable"
      defaultValue="private"
    >
      <RadioGroupFieldOption
        value="private"
        label="Private"
        description="Only invited members can view this project."
      />
      <RadioGroupFieldOption
        value="workspace"
        label="Workspace"
        description="Everyone in the workspace can find and open it."
      />
      <RadioGroupFieldOption
        value="public"
        label="Public"
        description="Anyone with the link can view the project."
      />
    </RadioGroupField>
  );
}

Disabled

disabled mutes the rows and blocks selection; set it on the group or on a single option.

Priority
Show code
import {
  RadioGroupField,
  RadioGroupFieldOption,
} from "@makeplane/propel/components/radio-group-field";

export default function DisabledDemo() {
  return (
    <RadioGroupField
      name="priority"
      label="Priority"
      size="lg"
      density="comfortable"
      defaultValue="low"
      disabled
    >
      <RadioGroupFieldOption value="low" label="Low" />
      <RadioGroupFieldOption value="medium" label="Medium" />
      <RadioGroupFieldOption value="high" label="High" />
    </RadioGroupField>
  );
}

Controlled

Selected: low
Show code
import { Field, FieldLabel } from "@makeplane/propel/components/field";
import { RadioGroup } from "@makeplane/propel/components/radio";
import { RadioGroupFieldOption } from "@makeplane/propel/components/radio-group-field";
import * as React from "react";

export default function ControlledDemo() {
  const [priority, setPriority] = React.useState("low");

  return (
    <div className="flex flex-col gap-3">
      <Field name="priority">
        <FieldLabel size="lg" inset={false}>
          Priority
        </FieldLabel>
        <RadioGroup
          density="comfortable"
          value={priority}
          onValueChange={(value) => setPriority(String(value))}
        >
          <RadioGroupFieldOption size="lg" value="low" label="Low" />
          <RadioGroupFieldOption size="lg" value="medium" label="Medium" />
          <RadioGroupFieldOption size="lg" value="high" label="High" />
        </RadioGroup>
      </Field>
      <output className="text-body-xs-regular text-secondary">Selected: {priority}</output>
    </div>
  );
}

API Reference

Radio

The ready-made radio option: grafts Base UI's `Radio` behavior onto the styled `Radio` ring and `RadioIndicator` dot. The 16px ring and 8px inner dot follow Figma node 1838-11057; the selected and disabled states come from the primitive. Use `disabled` for a non-editable (read-only) option. Must be rendered inside a `RadioGroup`.

PropTypeDefaultDescription
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, RadioRootState>Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render.

RadioGroup

Groups a set of `Radio` options so at most one can be selected at a time. Grafts Base UI's radio-group behavior (single-select state + roving focus) onto the styled `RadioGroup` frame, which owns the required row-spacing `density`.

PropTypeDefaultDescription
density(required)"comfortable" | "compact"Spacing between radio options.
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, RadioGroupState>Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render.