Radio Group
A set of checkable buttons (known as radio buttons) where no more than one of the buttons can be checked at a time.
Pair with Field.Set and Field.Legend for grouped label/description/error wiring in forms. RadioGroup keeps its own name prop on RadioGroup.Root:
Or render the control on its own:
Default
Laborum esse cillum incididunt est dolore.
Comfortable
Ea laboris tempor laborum officia ea adipisicing exercitation.
Compact
Adipisicing est dolore velit magna dolor voluptate velit.
Roomy
Tempor dolore Lorem exercitation id nisi aliquip elit.
Mixed
Only new workspace members are required to use SSO. Existing members can still log in with other methods.
Strict
All workspace members are required to log in with SSO.
Newsletter
Last message sent an hour ago
621 users
Existing Customers
Last message sent 2 weeks ago
1200 users
Trial Users
Last message sent 4 days ago
2740 Users
Rich option layout with Choice
Choice gives each radio option the same indicator-left / title-over-description layout used across mantle, without hand-rolling the flexbox: put RadioGroup.Indicator in Choice.Indicator and the copy in Choice.Content.
Free
Up to 3 projects and 1 member.
Pro
Unlimited projects and up to 25 members.
Use Choice.Title here, not Choice.Label: the whole RadioGroup.Item is the click target, and a <label htmlFor> can't associate with the radio's role="radio" element. Inside any radio item (Item, ListItem, Card, or Button), Choice.Title and Choice.Description register their ids with the radio. The radio's aria-labelledby points at the title, so the option's accessible name is the title alone, and its aria-describedby points at the description. Without that wiring, role="radio" would flatten both texts into one name. A plain RadioGroup.ItemContent has no title or description part to register, so its text still reads as one name; reach for Choice when the option carries helper text.
Give the RadioGroup itself an accessible name (an aria-label, as above, or a Field.Set / Field.Legend wrapper) so the group is announced as a named set rather than an anonymous radiogroup.
To bind the same group into a form, wrap it in a Field.Set / Field.Legend: the legend names the set, and keeping aria-label on RadioGroup.Root names the inner radiogroup role too.
With TanStack Form
Use @tanstack/react-form with zod to keep a radio group controlled. Use Field.Set and Field.Legend because the grouped choices answer one shared question.
Composition
RadioGroup supports several layout variants. Compose the parts together to build your own:
Polymorphism
RadioGroup.ItemContent accepts asChild. When true it renders its single child instead of its default <div>, forwarding class names, data-* attributes, and ref onto that child. Reach for it when the title-and-description block beside a radio needs to be a specific element, such as a <p> or a link wrapping the whole content area. Do not reach for a <label htmlFor>: each item is a div[role="radio"], which for cannot bind, and the item's text content is already its accessible name.
The rest of the family deliberately does not take asChild. RadioGroup.Root, List, and ButtonGroup own the group's roving-focus and arrow-key contract; Item, ListItem, Card, and Button each render a div[role="radio"] with its keyboard handling, and Indicator paints the control itself. When the group has a name, Headless UI renders one hidden <input type="radio"> for form submission. For a richer option layout, compose Choice inside RadioGroup.Item (see Rich option layout with Choice) rather than swapping these elements out.
API Reference
RadioGroup.Root
A group of radio items. Manages state so only one item can be selected at a time. Unstyled and simple.
All props from Headless UI RadioGroup, including:
RadioGroup.Item
A simple radio item. The conventional use-case for basic radio options. Must be a child of RadioGroup.Root. Inside Field.Control, the item picks up aria-invalid, aria-errormessage, and aria-describedby. A Choice.Title inside names it through aria-labelledby, and a Choice.Description describes it through aria-describedby.
RadioGroup.Indicator
The selection indicator for any radio item. By default, renders a circle that changes color when checked. Use as a child of RadioGroup.Item, RadioGroup.ListItem, or RadioGroup.Card.
Accepts a render-props function (context) => ReactNode as children for custom indicators. The context includes checked, disabled, focus, hover, and autofocus.
RadioGroup.ItemContent
The content wrapper for any radio item. Wrap labels, descriptions, or other content inside.
All props from div, plus:
RadioGroup.ButtonGroup
An inline group of radio buttons rendered as a horizontal segmented control. Use RadioGroup.Button as direct children.
Each segment keeps its label on one line and grows to fit it. Keep labels to one or two words. If the labels do not fit the width of the layout, use RadioGroup.Root or RadioGroup.List instead.
Same props as RadioGroup.Root.
RadioGroup.Button
A radio button used inside RadioGroup.ButtonGroup for inline grouped radio options. Inside Field.Control, the item picks up aria-invalid, aria-errormessage, and aria-describedby. A Choice.Title inside names it through aria-labelledby, and a Choice.Description describes it through aria-describedby.
RadioGroup.List
A group of radio list items with connected borders. Use RadioGroup.ListItem as direct children.
Same props as RadioGroup.Root.
RadioGroup.ListItem
A radio list item used inside RadioGroup.List for connected list-style radio options with borders and padding. Inside Field.Control, the item picks up aria-invalid, aria-errormessage, and aria-describedby. A Choice.Title inside names it through aria-labelledby, and a Choice.Description describes it through aria-describedby.
RadioGroup.Card
A radio card item with enhanced styling for card-based radio options. Inside Field.Control, the item picks up aria-invalid, aria-errormessage, and aria-describedby. A Choice.Title inside names it through aria-labelledby, and a Choice.Description describes it through aria-describedby.
RadioGroup.InputSandbox
A sandbox container for input elements composed within radio group items. A click inside it still selects the radio, then focus returns to the input. Keys other than Enter and Tab stop here, so typing does not move the selection. When the item is disabled or unchecked, the input leaves the tab order.