Skip to main content
BETA
View Zag.js on Github
Join the Discord server

Radio Group

A radio group allows users to make a single choice from a select number of option

Fruits

Properties

Features

  • Syncs with disabled state of fieldset
  • Syncs with form reset events
  • Can programmatically set radio group value
  • Can programmatically focus and blur radio items

Installation

To use the radio machine in your project, run the following command in your command line:

npm install @zag-js/radio @zag-js/react # or yarn add @zag-js/radio @zag-js/react

This command will install the framework agnostic radio group logic and the reactive utilities for your framework of choice.

Anatomy

To set up the radio group correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

On a high level, the radio group consists of:

  • Root: The root container for the radio group
  • Label: The label that gives the user information on the radio group
  • Item: The root container for the each radio item
  • Item Label: The label that gives the user information on each radio item
  • Item Control: The element that visually represents the each radio item.
  • Item Input: The native html input that is visually hidden in each radio item.

Usage

First, import the radio group package into your project

import * as radio from "@zag-js/radio"

The radio package exports two key functions:

  • machine — The state machine logic for the radio widget.
  • connect — The function that translates the machine's state to JSX attributes and event handlers.

You'll also need to provide a unique id to the useSetup hook. This is used to ensure that every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the radio machine in your project 🔥

import * as radio from "@zag-js/radio" import { useMachine, normalizeProps } from "@zag-js/react" const items = [ { id: "apple", label: "Apples" }, { id: "orange", label: "Oranges" }, { id: "mango", label: "Mangoes" }, { id: "grape", label: "Grapes" }, ] function Radio() { const [state, send] = useMachine(radio.machine({ id: "1" })) const api = radio.connect(state, send, normalizeProps) return ( <div {...api.rootProps}> <h3 {...api.labelProps}>Fruits</h3> {items.map((opt) => ( <label key={opt.id} {...api.getItemProps({ value: opt.id })}> <span {...api.getItemLabelProps({ value: opt.id })}>{opt.label}</span> <input {...api.getItemInputProps({ value: opt.id })} /> <div {...api.getItemControlProps({ value: opt.id })} /> </label> ))} </div> ) }

Disabling the radio group

To make a radio group disabled, set the context's disabled property to true

const [state, send] = useMachine( radio.machine({ disabled: true, }), )

Readonly radio group

To make a radio group readonly, set the context's readonly property to true

const [state, send] = useMachine( radio.machine({ readonly: true, }), )

Setting the initial value

To set the radio group's initial value, set the context's value property to the value of the radio item to be selected by default

const [state, send] = useMachine( radio.machine({ value: "apple", }), )

Listening for changes

When the radio group value changes, the onChange callback is invoked.

const [state, send] = useMachine( radio.machine({ onChange({ value }) { console.log("radio value is:", value) // 'apple' | 'orange' | 'grape' }, }), )

Methods and Properties

The radio's api provides properties and methods you can use to programmatically read and set the radio group's value.

PropertyDescription
valueValue of the radio group - checked radio item
setValueMethid to set the value of the radio group
focusFunction used to focus radio group items, following the WAI-ARIA guidelines
blurFunction used to blur any focused radio group item
const api = connect(state, send) api.value // 'apple' | 'orange' | 'grape' api.setValue("pears") api.value // pears

Usage within forms

To use radio group within forms, use the exposed inputProps from the connect function and ensure you pass name value to the machine's context. It will render a hidden input and ensure the value changes get propagated to the form correctly.

const [state, send] = useMachine( radio.machine({ name: "fruits", }), )

Styling guide

Earlier, we mentioned that each radio part has a data-part attribute added to them to select and style them in the DOM.

Focused State

When the radio input is focused, the data-focus attribute is added to the root, control and label parts.

[data-part="item"][data-focus] { /* styles for item focus state */ } [data-part="item-control"][data-focus] { /* styles for item control focus state */ } [data-part="item-label"][data-focus] { /* styles for item label focus state */ }

Disabled State

When the radio is disabled, the data-disabled attribute is added to the root, control and label parts.

[data-part="item"][data-disabled] { /* styles for item disabled state */ } [data-part="item-control"][data-disabled] { /* styles for item control disabled state */ } [data-part="item-label"][data-disabled] { /* styles for item label disabled state */ }

Invalid State

When the radio is invalid, the data-invalid attribute is added to the root, control and label parts.

[data-part="item"][data-invalid] { /* styles for item invalid state */ } [data-part="item-control"][data-invalid] { /* styles for item control invalid state */ } [data-part="item-label"][data-invalid] { /* styles for item label invalid state */ }

Edit this page on GitHub

On this page