Skip to content

RadioGroup

A set of options where exactly one is chosen. Use it when each option needs a sentence of its own, or when every option should be visible at once.

tsx
import { Radio, RadioGroup } from 'neba';

<RadioGroup label="Plan" defaultValue="team">
  <Radio value="starter" label="Starter" />
  <Radio value="team" label="Team" />
</RadioGroup>;

Props

RadioGroup

PropTypeDefaultDescription
sizeshared'xs' | 'sm' | 'md' | 'lg' | 'xl''md'Height and type scale
colorshared'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'Semantic colour role. Set on the group, inherited by every Radio
orientationshared'horizontal' | 'vertical''vertical'Which way the options stack. Vertical by default: a row breaks the moment one label is long
labelReactNodeThe label, wired to the control by Base UI's Field
descriptionReactNodeHelper text
errorReactNodeError message. Its presence turns the control invalid and re-points the colour family at danger
invalidboolean!!errorForces the invalid state without a message, for when a form library owns validity
valueValueThe chosen value. Use with onValueChange for a controlled group
defaultValueValueThe initial value, for an uncontrolled group
onValueChange(value: Value, details) => voidCalled when the chosen option changes
namestringIdentifies the field when a form is submitted
requiredbooleanfalseOne option must be chosen before the form submits
readOnlybooleanfalseShown but not changeable. Keeps its colour and edge, drains the saturation
disabledbooleanfalseUnavailable. Drops the colour family for neutral grey
childrenReactNodeThe Radio options
classNamesNebaSlots<'label' | 'control' | 'description' | 'error'>Class names for the parts behind the root. The root itself is className, so there is no root key

value with onValueChange makes it controlled; defaultValue makes it uncontrolled.

Radio

PropTypeDefaultDescription
value * ValueIdentifies this option. Speaks the same language as the group’s value
labelReactNodeThe text beside the dot
descriptionReactNodeHelper text under the label
readOnlybooleanfalseShown but not changeable. Keeps its colour and edge, drains the saturation
disabledbooleanfalseUnavailable. Drops the colour family for neutral grey
classNamesNebaSlots<'label' | 'control' | 'description' | 'indicator'>Class names for the parts behind the root. The root itself is className, so there is no root key

A Radio has no size and no color of its own: set them on RadioGroup and they reach every option.

With many options to fit into little space, use Select; to join two or three into one control, use SegmentedButton.

Examples

description

Each option can carry a sentence. However many lines the description takes, the dot stays aligned to the first line of the label.

orientation

vertical by default. Use horizontal only with short labels: one long label makes the row hard to read.

disabled · readOnly

Both can be set on the group or on an individual Radio. On the group, they reach every option.

classNames

The group and one option are styled separately, because they are two components. On RadioGroup, classNames takes label, control, description and error, where control is the element holding the options: the one carrying the row or column direction. On Radio it takes label, control, indicator and description, where control is the dot.

tsx
<RadioGroup label="Plan" classNames={{ control: 'gap-6' }}>
  <Radio value="team" label="Team" classNames={{ control: 'rounded-sm' }} />
</RadioGroup>

There is no error slot on Radio: a validity message belongs to the question, and the question is the group. See prop conventions for how a class name you pass resolves against the component's own.

Accessibility

  • The set takes one tab stop and the arrow keys move within it (a roving tab index).
  • The group's label becomes its accessible name.
  • Each Radio is wired to its label, so clicking the text selects it.

Released under the MIT License