Antares
Components

Radio

Accessible radio button component for mutually exclusive selections with keyboard navigation, validation states, and flexible layouts.

Installation

npm install --save @godaddy/antares

Props

NameTypeDefault
childrenReactNode

Label text for the radio button

className?string | undefined'react-aria-Radio'

Additional class names applied to the root element.

valuestring

The value of the radio button, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio#Value).

isDisabled?boolean | undefined

Whether the radio button is disabled or not. Shows that a selection exists, but is not available in that circumstance.

autoFocus?boolean | undefined

Whether the element should receive focus on render.

onFocus?((e: React.FocusEvent<Element, Element>) => void) | undefined

Handler that is called when the element receives focus.

onBlur?((e: React.FocusEvent<Element, Element>) => void) | undefined

Handler that is called when the element loses focus.

onFocusChange?((isFocused: boolean) => void) | undefined

Handler that is called when the element's focus status changes.

onKeyDown?((e: KeyboardEvent) => void) | undefined

Handler that is called when a key is pressed.

onKeyUp?((e: KeyboardEvent) => void) | undefined

Handler that is called when a key is released.

id?string | undefined

The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id).

onPress?((e: PressEvent) => void) | undefined

Handler that is called when the press is released over the target.

onPressStart?((e: PressEvent) => void) | undefined

Handler that is called when a press interaction starts.

onPressEnd?((e: PressEvent) => void) | undefined

Handler that is called when a press interaction ends, either over the target or when the pointer leaves the target.

onPressChange?((isPressed: boolean) => void) | undefined

Handler that is called when the press state changes.

onPressUp?((e: PressEvent) => void) | undefined

Handler that is called when a press is released over the target, regardless of whether it started on the target or not.

onClick?((e: React.MouseEvent<FocusableElement>) => void) | undefined

**Not recommended – use `onPress` instead.** `onClick` is an alias for `onPress` provided for compatibility with other libraries. `onPress` provides additional event details for non-mouse interactions.

inputRef?RefObject<HTMLInputElement | null> | undefined

A ref for the HTML input element.

onHoverStart?((e: HoverEvent) => void) | undefined

Handler that is called when a hover interaction starts.

onHoverEnd?((e: HoverEvent) => void) | undefined

Handler that is called when a hover interaction ends.

onHoverChange?((isHovering: boolean) => void) | undefined

Handler that is called when the hover state changes.

style?StyleOrFunction<RadioRenderProps> | undefined

The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. A function may be provided to compute the style based on component state.

render?DOMRenderFunction<"label", RadioRenderProps> | undefined

Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components. Requirements: - You must render the expected element type (e.g. if `<button>` is expected, you cannot render an `<a>`). - Only a single root DOM element can be rendered (no fragments). - You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.

slot?string | null | undefined

A slot name for the component. Slots allow the component to receive props from a parent component. An explicit `null` value indicates that the local props completely override all props received from a parent.

Examples

Basic

Select your plan
import { Radio, RadioGroup } from '@godaddy/antares';export function RadioBasicExample() {  return (    <RadioGroup label="Select your plan" defaultValue="basic">      <Radio value="basic">Basic</Radio>      <Radio value="standard">Standard</Radio>      <Radio value="premium">Premium</Radio>    </RadioGroup>  );}

Controlled

Select your plan

Current selection: standard

import { Radio, RadioGroup } from '@godaddy/antares';import { useState } from 'react';export function RadioControlledExample() {  const [selected, setSelected] = useState('standard');  return (    <>      <RadioGroup label="Select your plan" value={selected} onChange={setSelected}>        <Radio value="basic">Basic</Radio>        <Radio value="standard">Standard</Radio>        <Radio value="premium">Premium</Radio>      </RadioGroup>      <p>Current selection: {selected}</p>    </>  );}

Horizontal Layout

Select your plan
import { Radio, RadioGroup } from '@godaddy/antares';export function RadioHorizontalExample() {  return (    <RadioGroup label="Select your plan" defaultValue="standard" orientation="horizontal">      <Radio value="basic">Basic</Radio>      <Radio value="standard">Standard</Radio>      <Radio value="premium">Premium</Radio>    </RadioGroup>  );}

Disabled States

Disabled group
Individual disabled options
import { Radio, RadioGroup, Flex } from '@godaddy/antares';export function RadioDisabledExample() {  return (    <Flex direction="column" gap="md">      <RadioGroup label="Disabled group" defaultValue="basic" isDisabled>        <Radio value="basic">Basic</Radio>        <Radio value="standard">Standard</Radio>        <Radio value="premium">Premium</Radio>      </RadioGroup>      <RadioGroup label="Individual disabled options" defaultValue="standard">        <Radio value="basic" isDisabled>          Basic (disabled)        </Radio>        <Radio value="standard">Standard</Radio>        <Radio value="premium">Premium</Radio>      </RadioGroup>    </Flex>  );}

Required Indicator

Payment method
import { Radio, RadioGroup } from '@godaddy/antares';export function RadioRequiredExample() {  return (    <RadioGroup label="Payment method" isRequired defaultValue="credit">      <Radio value="credit">Credit Card</Radio>      <Radio value="paypal">PayPal</Radio>      <Radio value="bank">Bank Transfer</Radio>    </RadioGroup>  );}

Description Text

Notification preferences
Choose how you'd like to receive updates
import { Radio, RadioGroup } from '@godaddy/antares';export function RadioDescriptionExample() {  return (    <RadioGroup      label="Notification preferences"      description="Choose how you'd like to receive updates"      defaultValue="email"    >      <Radio value="email">Email</Radio>      <Radio value="sms">SMS</Radio>      <Radio value="push">Push Notifications</Radio>    </RadioGroup>  );}

Error State

Select shipping method
Please select a shipping method
import { Radio, RadioGroup } from '@godaddy/antares';export function RadioErrorExample() {  return (    <RadioGroup label="Select shipping method" isRequired isInvalid errorMessage="Please select a shipping method">      <Radio value="standard">Standard Shipping</Radio>      <Radio value="express">Express Shipping</Radio>      <Radio value="overnight">Overnight Shipping</Radio>    </RadioGroup>  );}

Aria Label

import { Radio, RadioGroup } from '@godaddy/antares';export function RadioAriaLabelExample() {  return (    <RadioGroup aria-label="Sort order" defaultValue="newest">      <Radio value="newest">Newest first</Radio>      <Radio value="oldest">Oldest first</Radio>      <Radio value="popular">Most popular</Radio>    </RadioGroup>  );}

Form Submission

Select your plan
import { Radio, RadioGroup } from '@godaddy/antares';import { type FormEvent, useState } from 'react';export function RadioFormExample() {  const [submittedValue, setSubmittedValue] = useState<string | null>(null);  function handleSubmit(event: FormEvent<HTMLFormElement>) {    event.preventDefault();    const value = new FormData(event.currentTarget).get('plan');    setSubmittedValue(value != null ? String(value) : null);  }  return (    <>      <form onSubmit={handleSubmit}>        <RadioGroup name="plan" label="Select your plan" defaultValue="standard">          <Radio value="basic">Basic</Radio>          <Radio value="standard">Standard</Radio>          <Radio value="premium">Premium</Radio>        </RadioGroup>        <button type="submit" style={{ marginTop: '1rem' }}>          Submit        </button>      </form>      {submittedValue && <p>Form submitted with value: {submittedValue}</p>}    </>  );}

Customization

Data Attributes

Components automatically add data attributes for styling different states:

RadioGroup Container: data-invalid, data-disabled, data-required, data-readonly, data-orientation

Radio Button: data-selected, data-hovered, data-pressed, data-focused, data-disabled

.my-radio-group [data-selected] {
  color: #09757a;
  font-weight: 500;
}

.my-radio-group[data-invalid] {
  border-color: #db1802;
}

.my-radio-group [data-focused] {
  outline: 2px solid #1976d2;
  outline-offset: 2px;
}

.my-radio-group [data-disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

Component Customization

Individual components can be styled by passing className props:

<RadioGroup label="Select plan" className="custom-radio-group">
  <Radio value="basic" className="custom-radio">
    Basic
  </Radio>
  <Radio value="premium" className="premium-radio">
    Premium
  </Radio>
</RadioGroup>

Accessibility

Keyboard Navigation

  • Tab: Moves focus to/from the radio group
  • Arrow Down/Right: Move to next radio button
  • Arrow Up/Left: Move to previous radio button
  • Space: Select the focused radio button

ARIA Support

  • role="radiogroup" on the container
  • role="radio" on each option
  • aria-checked indicates selection state
  • aria-disabled for disabled options
  • aria-required when selection is required
  • aria-invalid for validation errors

Troubleshooting

Selection Not Updating

// ❌ Wrong: Using both value and defaultValue
<RadioGroup value={value} defaultValue="basic">
  <Radio value="basic">Basic</Radio>
</RadioGroup>

// ✅ Controlled mode
<RadioGroup value={value} onChange={setValue}>
  <Radio value="basic">Basic</Radio>
</RadioGroup>

// ✅ Uncontrolled mode
<RadioGroup defaultValue="basic">
  <Radio value="basic">Basic</Radio>
</RadioGroup>

Styling Overrides Not Applying

/* ❌ May not have enough specificity */
.my-custom-radio {
  color: red;
}

/* ✅ Use data attributes and className for higher specificity */
.my-radio-group [data-selected] {
  color: red;
  font-weight: 600;
}

Keyboard Navigation Not Working

/* ❌ Don't remove focus outlines without replacement */
[data-focused] {
  outline: none;
}

/* ✅ Provide visible focus indicator */
.my-radio-group [data-focused] {
  outline: 2px solid #1976d2;
  outline-offset: 2px;
}

Best Practices

When to Use Radio Buttons

  • ✅ When there are 2-7 mutually exclusive options
  • ✅ When all options should be visible at once
  • ✅ When the decision is important and deserves space
  • ❌ For more than 7 options (use Select instead)
  • ❌ For binary yes/no choices (use Checkbox or Toggle instead)
  • ❌ When space is limited (use Select dropdown)

Label Guidelines

  • Use clear, concise labels
  • Keep labels short (1-3 words when possible)
  • Place the most common option first
  • Ensure labels are descriptive without being verbose

Validation

Always provide clear error messages:

<RadioGroup
  label="Select shipping method"
  isRequired
  isInvalid={!selectedShipping}
  errorMessage="Please select a shipping method"
>
  <Radio value="standard">Standard</Radio>
  <Radio value="express">Express</Radio>
</RadioGroup>

On this page