RadioGroup

RadioGroupGitLab
Um conjunto de botões de rádio para selecionar uma única opção em uma lista.

Uso

Use a diretiva v-model para controlar o valor do RadioGroup ou a prop default-value para definir o valor inicial quando você não precisa controlar o estado.

<script setup lang="ts">
const items = ref(['System', 'Light', 'Dark'])
const value = ref('System')
</script>

<template>
  <NRadioGroup v-model="value" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const items = ref(['System', 'Light', 'Dark'])
const value = ref('System')
</script>

<template>
  <NRadioGroup v-model="value" :items="items" />
</template>

Itens

Use a prop items como um array de strings ou números:

<script setup lang="ts">
const items = ref(['System', 'Light', 'Dark'])
const value = ref('System')
</script>

<template>
  <NRadioGroup v-model="value" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const items = ref(['System', 'Light', 'Dark'])
const value = ref('System')
</script>

<template>
  <NRadioGroup v-model="value" :items="items" />
</template>

Você também pode passar um array de objetos com as seguintes propriedades:

  • label?: string
  • description?: string
  • value?: string
  • disabled?: boolean
  • class?: any
  • ui?: { item?: ClassNameValue, container?: ClassNameValue, base?: ClassNameValue, 'indicator'?: ClassNameValue, wrapper?: ClassNameValue, label?: ClassNameValue, description?: ClassNameValue }

This is the first option.

This is the second option.

This is the third option.

<script setup lang="ts">
import type { RadioGroupItem } from '@nitro/ui'

const items = ref<RadioGroupItem[]>([
  {
    label: 'System',
    description: 'This is the first option.',
    value: 'system'
  },
  {
    label: 'Light',
    description: 'This is the second option.',
    value: 'light'
  },
  {
    label: 'Dark',
    description: 'This is the third option.',
    value: 'dark'
  }
])
const value = ref('system')
</script>

<template>
  <NRadioGroup v-model="value" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioGroupItem } from '@nitro/ui'

const items = ref<RadioGroupItem[]>([
  {
    label: 'System',
    description: 'This is the first option.',
    value: 'system'
  },
  {
    label: 'Light',
    description: 'This is the second option.',
    value: 'light'
  },
  {
    label: 'Dark',
    description: 'This is the third option.',
    value: 'dark'
  }
])
const value = ref('system')
</script>

<template>
  <NRadioGroup v-model="value" :items="items" />
</template>
Ao usar objetos, você precisa referenciar a propriedade value do objeto na diretiva v-model ou na prop default-value.

Chave de valor

Você pode alterar a propriedade usada para definir o valor usando a prop value-key. O padrão é value.

This is the first option.

This is the second option.

This is the third option.

<script setup lang="ts">
import type { RadioGroupItem } from '@nitro/ui'

const items = ref<RadioGroupItem[]>([
  {
    label: 'System',
    description: 'This is the first option.',
    id: 'system'
  },
  {
    label: 'Light',
    description: 'This is the second option.',
    id: 'light'
  },
  {
    label: 'Dark',
    description: 'This is the third option.',
    id: 'dark'
  }
])
const value = ref('light')
</script>

<template>
  <NRadioGroup v-model="value" value-key="id" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioGroupItem } from '@nitro/ui'

const items = ref<RadioGroupItem[]>([
  {
    label: 'System',
    description: 'This is the first option.',
    id: 'system'
  },
  {
    label: 'Light',
    description: 'This is the second option.',
    id: 'light'
  },
  {
    label: 'Dark',
    description: 'This is the third option.',
    id: 'dark'
  }
])
const value = ref('light')
</script>

<template>
  <NRadioGroup v-model="value" value-key="id" :items="items" />
</template>

Legenda

Use a prop legend para definir a legenda do RadioGroup.

Theme
<script setup lang="ts">
const items = ref(['System', 'Light', 'Dark'])
</script>

<template>
  <NRadioGroup legend="Theme" default-value="System" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const items = ref(['System', 'Light', 'Dark'])
</script>

<template>
  <NRadioGroup legend="Theme" default-value="System" :items="items" />
</template>

Cor

Use a prop color para alterar a cor do RadioGroup.

<script setup lang="ts">
const items = ref(['System', 'Light', 'Dark'])
</script>

<template>
  <NRadioGroup color="neutral" default-value="System" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const items = ref(['System', 'Light', 'Dark'])
</script>

<template>
  <NRadioGroup color="neutral" default-value="System" :items="items" />
</template>

Variante

Use a prop variant para alterar a variante do RadioGroup.

<script setup lang="ts">
import type { RadioGroupItem } from '@nitro/ui'

const items = ref<RadioGroupItem[]>([
  {
    label: 'Pro',
    value: 'pro',
    description: 'Tailored for indie hackers, freelancers and solo founders.'
  },
  {
    label: 'Startup',
    value: 'startup',
    description: 'Best suited for small teams, startups and agencies.'
  },
  {
    label: 'Enterprise',
    value: 'enterprise',
    description: 'Ideal for larger teams and organizations.'
  }
])
</script>

<template>
  <NRadioGroup color="primary" variant="table" default-value="pro" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { RadioGroupItem } from '@nitro/ui'

const items = ref<RadioGroupItem[]>([
  {
    label: 'Pro',
    value: 'pro',
    description: 'Tailored for indie hackers, freelancers and solo founders.'
  },
  {
    label: 'Startup',
    value: 'startup',
    description: 'Best suited for small teams, startups and agencies.'
  },
  {
    label: 'Enterprise',
    value: 'enterprise',
    description: 'Ideal for larger teams and organizations.'
  }
])
</script>

<template>
  <NRadioGroup color="primary" variant="table" default-value="pro" :items="items" />
</template>

Tamanho

Use a prop size para alterar o tamanho do RadioGroup.

<script setup lang="ts">
const items = ref(['System', 'Light', 'Dark'])
</script>

<template>
  <NRadioGroup size="xl" variant="list" default-value="System" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const items = ref(['System', 'Light', 'Dark'])
</script>

<template>
  <NRadioGroup size="xl" variant="list" default-value="System" :items="items" />
</template>

Orientação

Use a prop orientation para alterar a orientação do RadioGroup. O padrão é vertical.

<script setup lang="ts">
const items = ref(['System', 'Light', 'Dark'])
</script>

<template>
  <NRadioGroup orientation="horizontal" variant="list" default-value="System" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const items = ref(['System', 'Light', 'Dark'])
</script>

<template>
  <NRadioGroup orientation="horizontal" variant="list" default-value="System" :items="items" />
</template>

Indicador

Use a prop indicator para alterar a posição ou ocultar o indicador. O padrão é start.

<script setup lang="ts">
const items = ref(['System', 'Light', 'Dark'])
</script>

<template>
  <NRadioGroup indicator="end" variant="card" default-value="System" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const items = ref(['System', 'Light', 'Dark'])
</script>

<template>
  <NRadioGroup indicator="end" variant="card" default-value="System" :items="items" />
</template>

Desabilitado

Use a prop disabled para desabilitar o RadioGroup.

<script setup lang="ts">
const items = ref(['System', 'Light', 'Dark'])
</script>

<template>
  <NRadioGroup disabled default-value="System" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const items = ref(['System', 'Light', 'Dark'])
</script>

<template>
  <NRadioGroup disabled default-value="System" :items="items" />
</template>

API

Props

Prop Default Type
as'div'any

The element or component this component should render as.

legend string
valueKey'value' VK

When items is an array of objects, select the field to use as the value.

labelKey'label' keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>

When items is an array of objects, select the field to use as the label.

descriptionKey'description' keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>

When items is an array of objects, select the field to use as the description.

items T
modelValue GetItemValue<T, VK, undefined, NestedItem<T>>

The controlled value of the RadioGroup. Can be bind as v-model.

defaultValue GetItemValue<T, VK, undefined, NestedItem<T>>

The value of the RadioGroup when initially rendered. Use when you do not need to control the state of the RadioGroup.

size'md' "xs" | "sm" | "md" | "lg" | "xl"
variant'list' "card" | "list" | "table"
color'primary' "primary" | "secondary" | "accent" | "success" | "info" | "warning" | "error" | "neutral"
highlightboolean

Highlight the ring color like a focus state.

orientation'vertical' "horizontal" | "vertical"

The orientation the radio buttons are laid out.

indicator'start' "start" | "end" | "hidden"

Position of the indicator.

disabledboolean

When true, prevents the user from interacting with radio items.

loopboolean

When true, keyboard navigation will loop from last item to first, and vice versa.

name string

The name of the field. Submitted with its owning form as part of a name/value pair.

requiredboolean

When true, indicates that the user must set the value before the owning form can be submitted.

ui { root?: SlotClass; fieldset?: SlotClass; legend?: SlotClass; item?: SlotClass; container?: SlotClass; base?: SlotClass; indicator?: SlotClass; wrapper?: SlotClass; label?: SlotClass; description?: SlotClass; icon?: SlotClass; trailing?: SlotClass; }

Slots

Slot Type
legend{}
label{ item: Exclude<T[number] & { id: string; }, AcceptableValue>; modelValue: AcceptableValue; }
description{ item: Exclude<T[number] & { id: string; }, AcceptableValue>; modelValue: AcceptableValue; }
trailing{ item: Exclude<T[number] & { id: string; }, AcceptableValue>; modelValue: AcceptableValue; }

Emits

Event Type
update:modelValue[value: GetItemValue<T, VK, undefined, NestedItem<T>>]
change[event: Event]

Tema

app.config.ts
export default defineAppConfig({
  ui: {
    radioGroup: {
      slots: {
        root: 'relative',
        fieldset: 'flex gap-x-2',
        legend: 'mb-1 block font-medium text-default',
        item: 'flex items-start gap-2',
        container: 'flex items-center',
        base: 'rounded-full ring ring-inset ring-accented overflow-hidden focus-visible:outline-2 focus-visible:outline-offset-2',
        indicator: 'flex items-center justify-center size-full after:bg-default after:rounded-full',
        wrapper: 'w-full',
        label: 'block font-medium text-default',
        description: 'text-muted',
        icon: 'shrink-0',
        trailing: 'ml-auto'
      },
      variants: {
        color: {
          primary: {
            base: 'focus-visible:outline-primary',
            indicator: 'bg-primary'
          },
          secondary: {
            base: 'focus-visible:outline-secondary',
            indicator: 'bg-secondary'
          },
          accent: {
            base: 'focus-visible:outline-accent',
            indicator: 'bg-accent'
          },
          success: {
            base: 'focus-visible:outline-success',
            indicator: 'bg-success'
          },
          info: {
            base: 'focus-visible:outline-info',
            indicator: 'bg-info'
          },
          warning: {
            base: 'focus-visible:outline-warning',
            indicator: 'bg-warning'
          },
          error: {
            base: 'focus-visible:outline-error',
            indicator: 'bg-error'
          },
          neutral: {
            base: 'focus-visible:outline-inverted',
            indicator: 'bg-inverted'
          }
        },
        variant: {
          list: {
            item: ''
          },
          card: {
            item: 'border border-muted rounded-lg'
          },
          table: {
            item: 'border border-muted'
          }
        },
        orientation: {
          horizontal: {
            fieldset: 'flex-row'
          },
          vertical: {
            fieldset: 'flex-col'
          }
        },
        indicator: {
          start: {
            item: 'flex-row'
          },
          end: {
            item: 'flex-row-reverse'
          },
          hidden: {
            base: 'sr-only',
            wrapper: 'text-center'
          }
        },
        size: {
          xs: {
            fieldset: 'gap-y-0.5',
            legend: 'text-xs',
            base: 'size-3',
            item: 'text-xs',
            container: 'h-4',
            indicator: 'after:size-1',
            icon: 'size-4'
          },
          sm: {
            fieldset: 'gap-y-0.5',
            legend: 'text-xs',
            base: 'size-3.5',
            item: 'text-xs',
            container: 'h-4',
            indicator: 'after:size-1',
            icon: 'size-4'
          },
          md: {
            fieldset: 'gap-y-1',
            legend: 'text-sm',
            base: 'size-4',
            item: 'text-sm',
            container: 'h-5',
            indicator: 'after:size-1.5',
            icon: 'size-5'
          },
          lg: {
            fieldset: 'gap-y-1',
            legend: 'text-sm',
            base: 'size-4.5',
            item: 'text-sm',
            container: 'h-5',
            indicator: 'after:size-1.5',
            icon: 'size-5'
          },
          xl: {
            fieldset: 'gap-y-1.5',
            legend: 'text-base',
            base: 'size-5',
            item: 'text-base',
            container: 'h-6',
            indicator: 'after:size-2',
            icon: 'size-6'
          }
        },
        highlight: {
          true: ''
        },
        disabled: {
          true: {
            item: 'opacity-75',
            base: 'cursor-not-allowed',
            label: 'cursor-not-allowed',
            description: 'cursor-not-allowed'
          }
        },
        required: {
          true: {
            legend: "after:content-['*'] after:ms-0.5 after:text-error"
          }
        }
      },
      compoundVariants: [
        {
          size: 'xs',
          variant: [
            'card',
            'table'
          ],
          class: {
            item: 'p-2.5'
          }
        },
        {
          size: 'sm',
          variant: [
            'card',
            'table'
          ],
          class: {
            item: 'p-3'
          }
        },
        {
          size: 'md',
          variant: [
            'card',
            'table'
          ],
          class: {
            item: 'p-3.5'
          }
        },
        {
          size: 'lg',
          variant: [
            'card',
            'table'
          ],
          class: {
            item: 'p-4'
          }
        },
        {
          size: 'xl',
          variant: [
            'card',
            'table'
          ],
          class: {
            item: 'p-4.5'
          }
        },
        {
          orientation: 'horizontal',
          variant: 'table',
          class: {
            item: 'first-of-type:rounded-s-lg last-of-type:rounded-e-lg',
            fieldset: 'gap-0 -space-x-px'
          }
        },
        {
          orientation: 'vertical',
          variant: 'table',
          class: {
            item: 'first-of-type:rounded-t-lg last-of-type:rounded-b-lg',
            fieldset: 'gap-0 -space-y-px'
          }
        },
        {
          color: 'primary',
          variant: 'card',
          class: {
            item: 'has-data-[state=checked]:border-primary'
          }
        },
        {
          color: 'neutral',
          variant: 'card',
          class: {
            item: 'has-data-[state=checked]:border-inverted'
          }
        },
        {
          color: 'primary',
          variant: 'table',
          class: {
            item: 'has-data-[state=checked]:bg-primary/10 has-data-[state=checked]:border-primary/50 has-data-[state=checked]:z-[1]'
          }
        },
        {
          color: 'neutral',
          variant: 'table',
          class: {
            item: 'has-data-[state=checked]:bg-elevated has-data-[state=checked]:border-inverted/50 has-data-[state=checked]:z-[1]'
          }
        },
        {
          variant: [
            'card',
            'table'
          ],
          disabled: true,
          class: {
            item: 'cursor-not-allowed'
          }
        },
        {
          color: 'primary',
          highlight: true,
          class: {
            base: 'ring-primary'
          }
        },
        {
          color: 'neutral',
          highlight: true,
          class: {
            base: 'ring-inverted'
          }
        }
      ],
      defaultVariants: {
        size: 'md',
        color: 'primary',
        variant: 'list',
        indicator: 'start'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nitro/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        radioGroup: {
          slots: {
            root: 'relative',
            fieldset: 'flex gap-x-2',
            legend: 'mb-1 block font-medium text-default',
            item: 'flex items-start gap-2',
            container: 'flex items-center',
            base: 'rounded-full ring ring-inset ring-accented overflow-hidden focus-visible:outline-2 focus-visible:outline-offset-2',
            indicator: 'flex items-center justify-center size-full after:bg-default after:rounded-full',
            wrapper: 'w-full',
            label: 'block font-medium text-default',
            description: 'text-muted',
            icon: 'shrink-0',
            trailing: 'ml-auto'
          },
          variants: {
            color: {
              primary: {
                base: 'focus-visible:outline-primary',
                indicator: 'bg-primary'
              },
              secondary: {
                base: 'focus-visible:outline-secondary',
                indicator: 'bg-secondary'
              },
              accent: {
                base: 'focus-visible:outline-accent',
                indicator: 'bg-accent'
              },
              success: {
                base: 'focus-visible:outline-success',
                indicator: 'bg-success'
              },
              info: {
                base: 'focus-visible:outline-info',
                indicator: 'bg-info'
              },
              warning: {
                base: 'focus-visible:outline-warning',
                indicator: 'bg-warning'
              },
              error: {
                base: 'focus-visible:outline-error',
                indicator: 'bg-error'
              },
              neutral: {
                base: 'focus-visible:outline-inverted',
                indicator: 'bg-inverted'
              }
            },
            variant: {
              list: {
                item: ''
              },
              card: {
                item: 'border border-muted rounded-lg'
              },
              table: {
                item: 'border border-muted'
              }
            },
            orientation: {
              horizontal: {
                fieldset: 'flex-row'
              },
              vertical: {
                fieldset: 'flex-col'
              }
            },
            indicator: {
              start: {
                item: 'flex-row'
              },
              end: {
                item: 'flex-row-reverse'
              },
              hidden: {
                base: 'sr-only',
                wrapper: 'text-center'
              }
            },
            size: {
              xs: {
                fieldset: 'gap-y-0.5',
                legend: 'text-xs',
                base: 'size-3',
                item: 'text-xs',
                container: 'h-4',
                indicator: 'after:size-1',
                icon: 'size-4'
              },
              sm: {
                fieldset: 'gap-y-0.5',
                legend: 'text-xs',
                base: 'size-3.5',
                item: 'text-xs',
                container: 'h-4',
                indicator: 'after:size-1',
                icon: 'size-4'
              },
              md: {
                fieldset: 'gap-y-1',
                legend: 'text-sm',
                base: 'size-4',
                item: 'text-sm',
                container: 'h-5',
                indicator: 'after:size-1.5',
                icon: 'size-5'
              },
              lg: {
                fieldset: 'gap-y-1',
                legend: 'text-sm',
                base: 'size-4.5',
                item: 'text-sm',
                container: 'h-5',
                indicator: 'after:size-1.5',
                icon: 'size-5'
              },
              xl: {
                fieldset: 'gap-y-1.5',
                legend: 'text-base',
                base: 'size-5',
                item: 'text-base',
                container: 'h-6',
                indicator: 'after:size-2',
                icon: 'size-6'
              }
            },
            highlight: {
              true: ''
            },
            disabled: {
              true: {
                item: 'opacity-75',
                base: 'cursor-not-allowed',
                label: 'cursor-not-allowed',
                description: 'cursor-not-allowed'
              }
            },
            required: {
              true: {
                legend: "after:content-['*'] after:ms-0.5 after:text-error"
              }
            }
          },
          compoundVariants: [
            {
              size: 'xs',
              variant: [
                'card',
                'table'
              ],
              class: {
                item: 'p-2.5'
              }
            },
            {
              size: 'sm',
              variant: [
                'card',
                'table'
              ],
              class: {
                item: 'p-3'
              }
            },
            {
              size: 'md',
              variant: [
                'card',
                'table'
              ],
              class: {
                item: 'p-3.5'
              }
            },
            {
              size: 'lg',
              variant: [
                'card',
                'table'
              ],
              class: {
                item: 'p-4'
              }
            },
            {
              size: 'xl',
              variant: [
                'card',
                'table'
              ],
              class: {
                item: 'p-4.5'
              }
            },
            {
              orientation: 'horizontal',
              variant: 'table',
              class: {
                item: 'first-of-type:rounded-s-lg last-of-type:rounded-e-lg',
                fieldset: 'gap-0 -space-x-px'
              }
            },
            {
              orientation: 'vertical',
              variant: 'table',
              class: {
                item: 'first-of-type:rounded-t-lg last-of-type:rounded-b-lg',
                fieldset: 'gap-0 -space-y-px'
              }
            },
            {
              color: 'primary',
              variant: 'card',
              class: {
                item: 'has-data-[state=checked]:border-primary'
              }
            },
            {
              color: 'neutral',
              variant: 'card',
              class: {
                item: 'has-data-[state=checked]:border-inverted'
              }
            },
            {
              color: 'primary',
              variant: 'table',
              class: {
                item: 'has-data-[state=checked]:bg-primary/10 has-data-[state=checked]:border-primary/50 has-data-[state=checked]:z-[1]'
              }
            },
            {
              color: 'neutral',
              variant: 'table',
              class: {
                item: 'has-data-[state=checked]:bg-elevated has-data-[state=checked]:border-inverted/50 has-data-[state=checked]:z-[1]'
              }
            },
            {
              variant: [
                'card',
                'table'
              ],
              disabled: true,
              class: {
                item: 'cursor-not-allowed'
              }
            },
            {
              color: 'primary',
              highlight: true,
              class: {
                base: 'ring-primary'
              }
            },
            {
              color: 'neutral',
              highlight: true,
              class: {
                base: 'ring-inverted'
              }
            }
          ],
          defaultVariants: {
            size: 'md',
            color: 'primary',
            variant: 'list',
            indicator: 'start'
          }
        }
      }
    })
  ]
})
Some colors in compoundVariants are omitted for readability. Check out the source code on GitLab.

Changelog

No recent changes