Radio

NRadio component - use to create a radio input.

Basic

use NRadio to create a radio input.

AttributeDescription
v-modelReactive value of radio if checked or not.
valueThe value of the radio.
labelThe label of the radio.

To view the full list of attributes, see the Props section.

Preview
Code

Color

radio="{color}" - change the color of the radio.

You can use breakpoints such as sm:red, xs:green to change color based on screen size.

Preview
Code

Disabled

disabled - disable the radio.

Preview
Code

Form Group

You can use the NFormGroup component to create a radio group for the radio,

Read more about the NFormGroup component here.

Preview
Code
Please select your service provider
Please select your service provider

Service provider is required

Reverse

reverse - Switch the position of the radio and the label.

Preview
Code

Size

size="{size}" - change the size of the radio.

🚀 You can freely adjust the size of the radio using any size imaginable. No limits exist, and you can use breakpoints such as sm:sm, xs:lg to change size based on screen size.

Preview
Code

Rules

You can use the following rules to customize the radio if it is checked.

Rule NameDescriptionExample
n-checkedOnly apply the class if the radio is checked.n-checked:bg-red
Preview
Code

Customization

You can customize the radio using the una prop and utility classes.

Preview
Code
Value:

Slots

NameDescription
labelUse this slot to customize the label of the radio.
iconUse this slot to customize the icon of the radio when it is checked

Presets

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

type RadioPrefix = 'radio'

export const staticRadio: Record<`${RadioPrefix}-${string}` | RadioPrefix, string> = {
  // base
  'radio': 'radio-primary flex items-center transition-base border border-$c-ring rounded-full p-0.12em h-1em w-1em n-checked:border-brand n-checked:bg-brand',
  'radio-disabled': 'n-disabled',
  'radio-label': 'block text-sm font-medium leading-6',
  'radio-input': 'absolute w-full opacity-0',
  'radio-reverse': 'flex-row-reverse',
  'radio-peer-focus': 'peer-focus-(ring-2 ring-brand ring-offset-2 ring-offset-base)',

  // wrappers
  'radio-wrapper': 'gap-x-3 relative inline-flex items-center hover:cursor-pointer',

  // icon
  'radio-icon-base': 'm-auto opacity-0 text-inverted w-full h-full transition-base n-checked:opacity-100',
  'radio-icon': 'i-dot', // refer to general.ts
}

export const dynamicRadio = [
  [/^radio-(.*)$/, ([, 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 radio = [
  ...dynamicRadio,
  staticRadio,
]

Props

types/radio.ts
export interface NRadioProps {
  /**
   * Disable the radio.
   *
   * @default false
   */
  disabled?: boolean
  /**
   * 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.ts
   * @example
   * radio="green"
   */
  radio?: string
  /**
   * v-model binding value if the radio is checked.
   *
   * @default null
   */
  modelValue?: string | number | boolean | Record<string, any>
  /**
   * Add name attribute to the radio.
   *
   * @default null
   */
  name?: string
  /**
   * Manually set the id attribute.
   *
   * By default, the id attribute is generated randomly for accessibility reasons.
   *
   * @default randomId
   * @example
   * id="options"
   */
  id?: string
  /**
   * Manually set the for attribute.
   *
   * By default, the for attribute is synced with the id attribute for accessibility reasons.
   *
   * @default randomId
   * @example
   * for="options"
   */
  for?: string
  /**
   * Value of the radio.
   *
   * @example
   * value="1"
   */
  value?: string
  /**
   * Display label of the radio.
   *
   * @default null
   */
  label?: string
  /**
   * Allows you to change the size of the radio.
   *
   * @default size="sm"
   *
   * @example
   * size="sm" | size="2cm" | size="2rem" | size="2px"
   */
  size?: string

  /**
   * `UnaUI` preset configuration
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/radio.ts
   */
  una?: {
    radio?: string
    radioWrapper?: string
    radioLabel?: string
    radioIconBase?: string
    radioIcon?: string
  }
}

Components

Radio.vue
<script setup lang="ts">
import type { NRadioProps } from '../../types'
import { useVModel } from '@vueuse/core'
import { computed } from 'vue'
import { randomId } from '../../utils'
import NIcon from '../elements/Icon.vue'

defineOptions({
  inheritAttrs: false,
})

const props = withDefaults(
  defineProps<NRadioProps>(),
  {
    modelValue: '',
    disabled: false,
    una: () => ({
      radioIcon: 'radio-icon',
    }),
  },
)

const emit = defineEmits<{ (...args: any): void }>()

const slots = defineSlots<{
  default?: void
  icon?: any
}>()

const id = computed(() => props.id ?? randomId('radio'))

const model = useVModel(props, 'modelValue', emit, { passive: true })
</script>

<template>
  <label
    radio="wrapper"
    :for="props.for ?? id"
    :class="[
      una?.radioWrapper,
      {
        'radio-reverse': reverse,
        'radio-disabled': disabled,
      },
    ]"
    :checked="model === value || null"
    :disabled="disabled || null"
  >
    <input
      :id="id"
      v-model="model"
      type="radio"
      class="peer"
      radio="input"
      :disabled="disabled"
      :name="name"
      :value="value"
      @keypress.enter="model = value!"
    >
    <span
      :radio="radio"
      :size="size"
      class="radio radio-peer-focus"
      v-bind="$attrs"
    >
      <slot name="icon">
        <NIcon
          :class="[
            una.radioIconBase,
          ]"
          radio="icon-base icon-checked"
          :name="una.radioIcon!"
        />
      </slot>
    </span>
    <div
      v-if="slots.default || label"
      radio="label"
      :class="una?.radioLabel"
    >
      <slot>
        {{ label }}
      </slot>
    </div>
  </label>
</template>