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.

Examples

Basic

PropDefaultTypeDescription
defaultValue-stringThe value of the radio item that should be checked when initially rendered.
disabledfalsebooleanWhen true, prevents the user from interacting with radio items.
modelValue-stringThe controlled value of the radio item to check. Can be binded as v-model.
orientation-vertical, horizontalThe orientation of the component.
items-RadioGroupItem[]The radio items to render.
RadioGroupItem PropDefaultTypeDescription
value-stringThe value of the radio item.
disabledfalsebooleanWhen true, prevents the user from interacting with the radio item.
label-stringThe label of the radio item.
icon-stringThe icon of the radio item.
Preview
Code

Color

PropDefaultTypeDescription
radio-groupprimary{color}Set the color of the radio-group.
item.radioGroup-{color}Set the color of the specific radio item.
Preview
Code

Size and Square

PropDefaultTypeDescription
sizemdstringSets the size of the radio-group.
square2.5remstringSets the radio-group to a square shape with specified dimensions. This does not affect the size of the fallback value.
item.sizemdstringSets the size of the specific radio item.
item.square2.5remstringSets the specific radio item to a square shape with specified dimensions. This does not affect the size of the fallback value.

🚀 Adjust radio-group size freely using any size, breakpoints (e.g., sm:sm, xs:lg), or states (e.g., hover:lg, focus:3xl).

Preview
Code

Icon

PropDefaultTypeDescription
icon-stringThe icon to render.
item.icon-stringThe icon to render for the specific item.
Preview
Code

Rounded

PropDefaultTypeDescription
roundedmdstringSet the radio-group to be rounded.
item.roundedmdstringSet the specific radio item to be rounded.

🚀 Adjust radio-group rounded freely using any value, breakpoints (e.g., sm:sm, xs:lg), or states (e.g., hover:lg, focus:full).

Preview
Code

Slots

NamePropsDescription
defaultitemsThe item slot.
label-The label slot.
icon-The icon slot.
Preview
Code

Presets

shortcuts/radio-group.ts
import type { RuleContext } from '@unocss/core'
import type { Theme } from '@unocss/preset-uno'
import { parseColor } from '@unocss/preset-mini/utils'

type RadioGroupPrefix = 'radio-group'

export const staticRadioGroup: Record<`${RadioGroupPrefix}-${string}` | RadioGroupPrefix, string> = {
  // configurations
  'radio-group': 'gap-2 flex flex-wrap',
  'radio-group-orientation-vertical': 'flex-col',
  'radio-group-orientation-horizontal': 'flex-row',

  // components
  'radio-group-item-wrapper': 'flex items-center space-x-2',
  'radio-group-item': 'aspect-square rounded-full border border-brand text-brand shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-base disabled:n-disabled',

  'radio-group-indicator': 'flex items-center justify-center',
  'radio-group-indicator-icon-base': 'h-0.875em w-0.875em fill-brand',
  'radio-group-indicator-icon': 'i-dot',

  'radio-group-item-label': '',
}

export const dynamicRadioGroup = [
  [/^radio-group-(.*)$/, ([, body]: string[], { theme }: RuleContext<Theme>) => {
    const color = parseColor(body, theme)
    if ((color?.cssColor?.type === 'rgb' || color?.cssColor?.type === 'rgba') && color.cssColor.components)
      return `n-${body}-600 dark:n-${body}-500`
  }],
]

export const radioGroup = [
  ...dynamicRadioGroup,
  staticRadioGroup,
]

Props

types/radio-group.ts
import type { RadioGroupItemProps, RadioGroupRootProps } from 'radix-vue'
import type { HTMLAttributes } from 'vue'

interface BaseProps {
  class?: HTMLAttributes['class']
  /**
   * Set the size of the avatar.
   */
  size?: HTMLAttributes['class']
  /**
   * Set the height and width of the avatar.
   */
  square?: HTMLAttributes['class']
  /**
   * Set the border radius of the avatar.
   */
  rounded?: HTMLAttributes['class']
  /**
   * Update the icon of the radio.
   */
  icon?: HTMLAttributes['class']
}

export interface NRadioGroupProps extends BaseProps, RadioGroupRootProps {
  items?: NRadioGroupItemProps[]
  /**
   * Switch the position of label and radio.
   *
   * @default false
   */
  reverse?: boolean
  /**
   * Allows you to add `UnaUI` radio preset properties,
   * Think of it as a shortcut for adding options or variants to the preset if available.
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/radio-group.ts
   * @example
   * radio-group="green"
   */
  radioGroup?: HTMLAttributes['class']
  /**
   * `UnaUI` preset configuration
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/radio.ts
   */
  una?: NRadioGroupUnaProps
}

export interface NRadioGroupItemProps extends BaseProps, RadioGroupItemProps {
  label?: string
  /**
   * Allows you to add `UnaUI` radio preset properties,
   * Think of it as a shortcut for adding options or variants to the preset if available.
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/radio-group.ts
   * @example
   * radio-group="green"
   */
  radioGroup?: HTMLAttributes['class']

  una?: NRadioGroupUnaProps
}

export interface NRadioGroupUnaProps {
  radioGroup?: HTMLAttributes['class']

  radioGroupItemWrapper?: HTMLAttributes['class']
  radioGroupItem?: HTMLAttributes['class']
  radioGroupItemLabel?: HTMLAttributes['class']

  radioGroupIndicator?: HTMLAttributes['class']
  radioGroupIndicatorIcon?: HTMLAttributes['class']
}

Components

RadioGroup.vue
RadioGroupItem.vue
<script setup lang="ts">
import type { NRadioGroupProps } from '../../../types'
import { reactivePick } from '@vueuse/core'
import { RadioGroupRoot, type RadioGroupRootEmits, useForwardPropsEmits } from 'radix-vue'
import { cn } from '../../../utils'
import RadioGroupItem from './RadioGroupItem.vue'

const props = withDefaults(defineProps<NRadioGroupProps>(), {
  radioGroup: 'primary',
  size: 'md',
  square: '1em',
})
const emits = defineEmits<RadioGroupRootEmits>()

const rootProps = reactivePick(props, [
  'as',
  'asChild',
  'defaultValue',
  'dir',
  'disabled',
  'loop',
  'modelValue',
  'name',
  'orientation',
  'required',
])

const forwarded = useForwardPropsEmits(rootProps, emits)
</script>

<template>
  <RadioGroupRoot
    :class="cn(
      'radio-group',
      orientation === 'horizontal' ? 'radio-group-orientation-horizontal' : 'radio-group-orientation-vertical',
      una?.radioGroup,
      props.class,
    )"
    v-bind="forwarded"
  >
    <slot>
      <RadioGroupItem
        v-for="item in items"
        :key="item.value"
        v-bind="{ rounded, icon, size, square, radioGroup, ...item }"
        :una="{ ...una, ...item.una }"
      />
    </slot>
  </RadioGroupRoot>
</template>