表单

Radio Group 单项选择

用于单项选择场景的 MoriUI 组件。

资源

导入

import { RadioGroup, RadioGroupItem } from 'moriui'

组合方式

RadioGroup 管理唯一选中值,RadioGroupItem 以必填 value 标识选项;标签、说明与错误由 Field 组合。

受控与默认值

使用 v-model 持有当前 AcceptableValue;无需受控时可用 defaultValue 设置初始选择。

禁用与无效

disabled 可设置在整组或单个 Item;无效项使用 aria-invalid,外围 Field 使用 data-invalid。

RTL

dir 影响方向键顺序与内容阅读方向,Reka UI 负责 roving focus 和循环导航。

示例

概览

用 v-model 在三个界面密度中保持唯一选择。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import { Field, FieldLabel, RadioGroup, RadioGroupItem } from 'moriui'

  const density = shallowRef('comfortable')
</script>

<template>
  <RadioGroup v-model="density" aria-label="界面密度" class="w-fit">
    <Field v-for="item in [['default', '默认'], ['comfortable', '舒适'], ['compact', '紧凑']]" :key="item[0]" orientation="horizontal">
      <RadioGroupItem :id="`density-${item[0]}`" :value="item[0]" />
      <FieldLabel :for="`density-${item[0]}`">
        {{ item[1] }}
      </FieldLabel>
    </Field>
  </RadioGroup>
</template>

说明

FieldContent 为每个选项组合标签与帮助文字。

适合大多数场景的标准间距。

为内容保留更多呼吸空间。

适合信息密集的操作界面。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import {
    Field,
    FieldContent,
    FieldDescription,
    FieldLabel,
    RadioGroup,
    RadioGroupItem
  } from 'moriui'

  const density = shallowRef('comfortable')
  const options = [
    { value: 'default', label: '默认', description: '适合大多数场景的标准间距。' },
    { value: 'comfortable', label: '舒适', description: '为内容保留更多呼吸空间。' },
    { value: 'compact', label: '紧凑', description: '适合信息密集的操作界面。' }
  ]
</script>

<template>
  <RadioGroup v-model="density" class="w-full max-w-xs">
    <Field v-for="item in options" :key="item.value" orientation="horizontal">
      <RadioGroupItem :id="`description-${item.value}`" :value="item.value" />
      <FieldContent>
        <FieldLabel :for="`description-${item.value}`">
          {{ item.label }}
        </FieldLabel>
        <FieldDescription>{{ item.description }}</FieldDescription>
      </FieldContent>
    </Field>
  </RadioGroup>
</template>

选择卡片

FieldLabel 包裹整行内容,扩大可点击区域。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import {
    Field,
    FieldContent,
    FieldDescription,
    FieldLabel,
    FieldTitle,
    RadioGroup,
    RadioGroupItem
  } from 'moriui'

  const plan = shallowRef('plus')
  const plans = [
    { value: 'plus', title: 'Plus', description: '适合个人与小型团队。' },
    { value: 'pro', title: 'Pro', description: '适合持续增长的业务。' },
    { value: 'enterprise', title: 'Enterprise', description: '适合大型团队与企业。' }
  ]
</script>

<template>
  <RadioGroup v-model="plan" class="w-full max-w-sm">
    <FieldLabel v-for="item in plans" :key="item.value" :for="`plan-${item.value}`">
      <Field orientation="horizontal">
        <FieldContent>
          <FieldTitle>{{ item.title }}</FieldTitle>
          <FieldDescription>{{ item.description }}</FieldDescription>
        </FieldContent>
        <RadioGroupItem :id="`plan-${item.value}`" :value="item.value" />
      </Field>
    </FieldLabel>
  </RadioGroup>
</template>

字段集

FieldSet 与 FieldLegend 建立订阅方案的语义分组。

订阅方案

年付与终身方案可节省更多费用。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import {
    Field,
    FieldDescription,
    FieldLabel,
    FieldLegend,
    FieldSet,
    RadioGroup,
    RadioGroupItem
  } from 'moriui'

  const plan = shallowRef('monthly')
</script>

<template>
  <FieldSet class="w-full max-w-xs">
    <FieldLegend variant="label">
      订阅方案
    </FieldLegend>
    <FieldDescription>年付与终身方案可节省更多费用。</FieldDescription>
    <RadioGroup v-model="plan">
      <Field v-for="item in [['monthly', '月付(¥68/月)'], ['yearly', '年付(¥680/年)'], ['lifetime', '终身(¥1,980)']]" :key="item[0]" orientation="horizontal">
        <RadioGroupItem :id="`subscription-${item[0]}`" :value="item[0]" />
        <FieldLabel :for="`subscription-${item[0]}`">
          {{ item[1] }}
        </FieldLabel>
      </Field>
    </RadioGroup>
  </FieldSet>
</template>

禁用

单个 disabled 项与可选项共存。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import { Field, FieldLabel, RadioGroup, RadioGroupItem } from 'moriui'

  const option = shallowRef('option-2')
</script>

<template>
  <RadioGroup v-model="option" class="w-fit">
    <Field orientation="horizontal" data-disabled>
      <RadioGroupItem id="disabled-option-1" value="option-1" disabled />
      <FieldLabel for="disabled-option-1">
        不可选选项
      </FieldLabel>
    </Field>
    <Field orientation="horizontal">
      <RadioGroupItem id="disabled-option-2" value="option-2" />
      <FieldLabel for="disabled-option-2">
        选项二
      </FieldLabel>
    </Field>
    <Field orientation="horizontal">
      <RadioGroupItem id="disabled-option-3" value="option-3" />
      <FieldLabel for="disabled-option-3">
        选项三
      </FieldLabel>
    </Field>
  </RadioGroup>
</template>

无效

aria-invalid 与 Field data-invalid 同步错误状态。

通知偏好

请重新确认接收通知的方式。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import {
    Field,
    FieldDescription,
    FieldLabel,
    FieldLegend,
    FieldSet,
    RadioGroup,
    RadioGroupItem
  } from 'moriui'

  const channel = shallowRef('email')
</script>

<template>
  <FieldSet class="w-full max-w-xs">
    <FieldLegend variant="label">
      通知偏好
    </FieldLegend>
    <FieldDescription>请重新确认接收通知的方式。</FieldDescription>
    <RadioGroup v-model="channel">
      <Field
        v-for="item in [['email', '仅邮件'], ['sms', '仅短信'], ['both', '邮件和短信']]"
        :key="item[0]"
        orientation="horizontal"
        data-invalid
      >
        <RadioGroupItem :id="`invalid-${item[0]}`" :value="item[0]" aria-invalid="true" />
        <FieldLabel :for="`invalid-${item[0]}`">
          {{ item[1] }}
        </FieldLabel>
      </Field>
    </RadioGroup>
  </FieldSet>
</template>

RTL

阿拉伯语选项使用 RTL 方向与正确的键盘顺序。

تباعد قياسي لمعظم حالات الاستخدام.

مساحة أكبر بين العناصر.

تباعد أدنى للتخطيطات الكثيفة.

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import {
    Field,
    FieldContent,
    FieldDescription,
    FieldLabel,
    RadioGroup,
    RadioGroupItem
  } from 'moriui'

  const density = shallowRef('comfortable')
  const options = [
    { value: 'default', label: 'افتراضي', description: 'تباعد قياسي لمعظم حالات الاستخدام.' },
    { value: 'comfortable', label: 'مريح', description: 'مساحة أكبر بين العناصر.' },
    { value: 'compact', label: 'مضغوط', description: 'تباعد أدنى للتخطيطات الكثيفة.' }
  ]
</script>

<template>
  <RadioGroup v-model="density" class="w-full max-w-xs" dir="rtl">
    <Field v-for="item in options" :key="item.value" orientation="horizontal">
      <RadioGroupItem :id="`rtl-density-${item.value}`" :value="item.value" />
      <FieldContent>
        <FieldLabel :for="`rtl-density-${item.value}`">
          {{ item.label }}
        </FieldLabel>
        <FieldDescription>{{ item.description }}</FieldDescription>
      </FieldContent>
    </Field>
  </RadioGroup>
</template>

API

属性 类型 默认值 说明
RadioGroup v-modelAcceptableValueundefined当前唯一选中值。
RadioGroup defaultValueAcceptableValueundefined非受控初始选中值。
RadioGroup disabled / requiredbooleanfalse整组禁用与表单必填语义。
RadioGroup orientation'horizontal' | 'vertical'undefined方向键导航方向。
RadioGroup dir / loop'ltr' | 'rtl' / boolean继承 / true阅读方向与循环键盘导航。
RadioGroupItem valueAcceptableValue必填的选项值。
RadioGroupItem disabledbooleanfalse单独禁用当前选项。

无障碍说明

RadioGroup 复用 Reka UI 的 radiogroup/radio ARIA、方向键、Space 选择与 roving focus。整组应有 FieldLegend 或 aria-label,每个 Item 必须关联可读标签;错误同时使用 aria-invalid 与文字说明。

关联组件

这个组件暂时没有登记关联条目。