Menu

Site and documentation links

Search documentation

Type to filter pages and sections. Use the arrow keys to move and Enter to open.

    Radio Group

    A set of options where exactly one can be checked.

    View code
    import { RadioGroup, RadioGroupIndicator, RadioGroupItem } from '@syncclouds/ui'
    
    const REGIONS = ['Frankfurt', 'Virginia', 'Singapore']
    
    export function RadioGroupDemo() {
      return (
        <RadioGroup aria-label="Region" defaultValue="virginia">
          {REGIONS.map(region => (
            <RadioGroupItem key={region} value={region.toLowerCase()}>
              <RadioGroupIndicator />
              {region}
            </RadioGroupItem>
          ))}
        </RadioGroup>
      )
    }

    Installation

    npm install @syncclouds/ui

    Usage

    import { RadioGroup, RadioGroupIndicator, RadioGroupItem } from '@syncclouds/ui'
    <RadioGroup aria-label="Region" defaultValue="virginia">
      <RadioGroupItem value="frankfurt">
        <RadioGroupIndicator />
        Frankfurt
      </RadioGroupItem>
      <RadioGroupItem value="virginia">
        <RadioGroupIndicator />
        Virginia
      </RadioGroupItem>
    </RadioGroup>

    Anatomy

    RadioGroup
    └── RadioGroupItem
        └── RadioGroupIndicator

    Horizontal

    View code
    import { RadioGroup, RadioGroupIndicator, RadioGroupItem } from '@syncclouds/ui'
    
    export function RadioGroupHorizontal() {
      return (
        <RadioGroup aria-label="Billing cycle" orientation="horizontal" defaultValue="monthly">
          <RadioGroupItem value="monthly">
            <RadioGroupIndicator />
            Monthly
          </RadioGroupItem>
          <RadioGroupItem value="yearly">
            <RadioGroupIndicator />
            Yearly
          </RadioGroupItem>
        </RadioGroup>
      )
    }

    Disabled

    Disable one item, or the whole group with disabled on RadioGroup.

    View code
    import { RadioGroup, RadioGroupIndicator, RadioGroupItem } from '@syncclouds/ui'
    
    export function RadioGroupDisabled() {
      return (
        <RadioGroup aria-label="Delivery" defaultValue="standard">
          <RadioGroupItem value="standard">
            <RadioGroupIndicator />
            Standard, 3 to 5 days
          </RadioGroupItem>
          <RadioGroupItem value="express">
            <RadioGroupIndicator />
            Express, next day
          </RadioGroupItem>
          <RadioGroupItem value="same-day" disabled>
            <RadioGroupIndicator />
            Same day (not in your area)
          </RadioGroupItem>
        </RadioGroup>
      )
    }

    In a form

    With name, the value submits with the form.

    Plan

    Not sent yet.

    View code
    'use client'
    
    import { useState, type FormEvent } from 'react'
    import { RadioGroup, RadioGroupIndicator, RadioGroupItem } from '@syncclouds/ui'
    
    /* With name, a hidden input carries the value into FormData. */
    export function RadioGroupForm() {
      const [sent, setSent] = useState<string | null>(null)
    
      const onSubmit = (event: FormEvent<HTMLFormElement>) => {
        event.preventDefault()
        setSent(String(new FormData(event.currentTarget).get('plan')))
      }
    
      return (
        <form onSubmit={onSubmit} className="flex flex-col items-start gap-4">
          <p id="plan-label" className="text-sm font-semibold">
            Plan
          </p>
          <RadioGroup aria-labelledby="plan-label" name="plan" defaultValue="team">
            {['Starter', 'Team', 'Enterprise'].map(plan => (
              <RadioGroupItem key={plan} value={plan.toLowerCase()}>
                <RadioGroupIndicator />
                {plan}
              </RadioGroupItem>
            ))}
          </RadioGroup>
          <button type="submit" className="rounded-md border border-current/40 px-3 py-1.5 text-sm font-medium">
            Submit
          </button>
          <p className="text-sm">{sent ? `Form sent plan=${sent}` : 'Not sent yet.'}</p>
        </form>
      )
    }

    Without the theme

    View code
    import { RadioGroup, RadioGroupItem } from '@syncclouds/ui'
    
    const SIZES = ['S', 'M', 'L', 'XL']
    
    export function RadioGroupUnstyled() {
      return (
        <RadioGroup aria-label="Size" orientation="horizontal" defaultValue="M" className="flex gap-2">
          {SIZES.map(size => (
            <RadioGroupItem
              key={size}
              value={size}
              className="flex size-11 items-center justify-center rounded-lg border border-zinc-300 text-sm font-semibold text-zinc-900 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 data-[state=checked]:border-indigo-600 data-[state=checked]:bg-indigo-600 data-[state=checked]:text-white dark:border-zinc-600 dark:text-zinc-100 dark:data-[state=checked]:border-indigo-400 dark:data-[state=checked]:bg-indigo-400 dark:data-[state=checked]:text-zinc-950"
            >
              {size}
            </RadioGroupItem>
          ))}
        </RadioGroup>
      )
    }

    Accessibility

    Follows the WAI-ARIA Radio Group pattern.

    KeysWhat they do
    TabMoves focus to the checked item. The group is one tab stop.
    Arrow keysMove to the next or previous item and check it, wrapping at the ends.
    SpaceChecks the focused item.
    • Enter never checks an item, so it can still submit a form.

    API reference

    Every part also accepts the props of the element it renders, including className and ref.

    RadioGrouprenders <div>

    The group. Name it with aria-label or aria-labelledby.

    PropTypeDefaultDescription
    valuestringnoneThe checked item, when you control it.
    defaultValuestring""The item checked at first.
    onValueChange(value: string) => voidnoneCalled when another item is checked.
    namestringnoneAdds a hidden input so the value submits with a form.
    disabledbooleanfalseDisables every item.
    orientation"horizontal" | "vertical"noneSets aria-orientation. All four arrow keys work either way.
    Data attributeValues
    data-orientation"horizontal" | "vertical"
    data-disabledpresent when disabled

    RadioGroupItemrenders <button>

    One option. Put its label text inside.

    PropTypeDefaultDescription
    valuestringnoneRequired. Identifies the item.
    disabledbooleanfalseDisables this item.
    Data attributeValues
    data-state"checked" | "unchecked"
    data-disabledpresent when disabled

    RadioGroupIndicatorrenders <span>

    The drawn circle. Purely visual; hidden from assistive technology.

    Data attributeValues
    data-state"checked" | "unchecked"
    Built by Syncclouds. Syncclouds UI is in development.