表单

Field 表单字段

用于表单字段场景的 MoriUI 组件。

资源

导入

import { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle } from 'moriui'

组合方式

单个 Field 组合 Label、控件、Description 与 Error;相关控件由 FieldGroup 和语义 FieldSet 组织。

结构

FieldContent 用于横向布局中的标题与说明;没有说明时不需要额外包装。

响应式布局

orientation 支持 vertical、horizontal、responsive;responsive 通过组件样式在合适容器宽度切换。

校验与错误

Field 使用 data-invalid,真实控件使用 aria-invalid,FieldError 以 role="alert" 输出去重后的错误。

示例

概览

组合字段组、字段集、分隔线与操作。

付款信息

所有交易均经过加密。

请输入 16 位卡号。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import {
    Button,
    Checkbox,
    Field,
    FieldDescription,
    FieldGroup,
    FieldLabel,
    FieldLegend,
    FieldSeparator,
    FieldSet,
    Input
  } from 'moriui'

  const sameAddress = shallowRef(true)
</script>

<template>
  <form class="w-full max-w-md">
    <FieldGroup>
      <FieldSet>
        <FieldLegend>付款信息</FieldLegend>
        <FieldDescription>所有交易均经过加密。</FieldDescription>
        <FieldGroup>
          <Field>
            <FieldLabel for="card-name">
              持卡人
            </FieldLabel><Input id="card-name" required placeholder="林晓" />
          </Field>
          <Field>
            <FieldLabel for="card-number">
              卡号
            </FieldLabel><Input
              id="card-number"
              required
              inputmode="numeric"
              placeholder="1234 5678 9012 3456"
            /><FieldDescription>请输入 16 位卡号。</FieldDescription>
          </Field>
        </FieldGroup>
      </FieldSet>
      <FieldSeparator />
      <Field orientation="horizontal">
        <Checkbox id="same-address" v-model="sameAddress" /><FieldLabel for="same-address">
          账单地址与收货地址相同
        </FieldLabel>
      </Field>
      <Field orientation="horizontal">
        <Button type="submit">
          提交
        </Button><Button type="button" variant="outline">
          取消
        </Button>
      </Field>
    </FieldGroup>
  </form>
</template>

输入框

标签、输入和说明的基础字段。

请选择唯一的用户名。

至少包含 8 个字符。

<script setup lang="ts">
  import {
    Field,
    FieldDescription,
    FieldGroup,
    FieldLabel,
    FieldSet,
    Input
  } from 'moriui'
</script>

<template>
  <FieldSet class="w-full max-w-xs">
    <FieldGroup>
      <Field>
        <FieldLabel for="username">
          用户名
        </FieldLabel><Input id="username" placeholder="Mori" /><FieldDescription>请选择唯一的用户名。</FieldDescription>
      </Field>
      <Field>
        <FieldLabel for="password">
          密码
        </FieldLabel><FieldDescription>至少包含 8 个字符。</FieldDescription><Input id="password" type="password" placeholder="••••••••" />
      </Field>
    </FieldGroup>
  </FieldSet>
</template>

多行输入

Textarea 与帮助文字组成反馈字段。

请描述遇到的问题或建议。

<script setup lang="ts">
  import { Field, FieldDescription, FieldLabel, Textarea } from 'moriui'
</script>

<template>
  <Field class="w-full max-w-xs">
    <FieldLabel for="feedback">
      反馈
    </FieldLabel><Textarea id="feedback" rows="4" placeholder="你的建议会帮助我们改进…" /><FieldDescription>请描述遇到的问题或建议。</FieldDescription>
  </Field>
</template>

选择框

MoriUI Select 可复用 Field 的标签、说明与布局。

选择你的工作部门。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import {
    Field,
    FieldDescription,
    FieldLabel,
    Select,
    SelectContent,
    SelectItem,
    SelectItemIndicator,
    SelectItemText,
    SelectTrigger,
    SelectValue,
    SelectViewport
  } from 'moriui'

  const department = shallowRef<string>()
</script>

<template>
  <Field class="w-full max-w-xs">
    <FieldLabel for="department">
      部门
    </FieldLabel>
    <Select v-model="department">
      <SelectTrigger id="department" aria-label="部门">
        <SelectValue placeholder="选择部门" />
      </SelectTrigger>
      <SelectContent>
        <SelectViewport>
          <SelectItem v-for="item in ['工程', '设计', '市场']" :key="item" :value="item">
            <SelectItemIndicator /><SelectItemText>{{ item }}</SelectItemText>
          </SelectItem>
        </SelectViewport>
      </SelectContent>
    </Select>
    <FieldDescription>选择你的工作部门。</FieldDescription>
  </Field>
</template>

滑块

标题与说明展示当前范围值。

预算范围

当前预算:¥500

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import {
    Field,
    FieldDescription,
    FieldTitle,
    Slider,
    SliderRange,
    SliderThumb,
    SliderTrack
  } from 'moriui'

  const budget = shallowRef([500])
</script>

<template>
  <Field class="w-full max-w-xs">
    <FieldTitle>预算范围</FieldTitle>
    <FieldDescription>当前预算:¥{{ budget[0] }}</FieldDescription>
    <Slider
      v-model="budget"
      :min="0"
      :max="1000"
      :step="10"
      aria-label="预算范围"
    >
      <SliderTrack><SliderRange /></SliderTrack><SliderThumb />
    </Slider>
  </Field>
</template>

字段集

FieldSet 与 Legend 建立语义分组。

地址信息

我们需要地址来配送订单。

<script setup lang="ts">
  import {
    Field,
    FieldDescription,
    FieldGroup,
    FieldLabel,
    FieldLegend,
    FieldSet,
    Input
  } from 'moriui'
</script>

<template>
  <FieldSet class="w-full max-w-sm">
    <FieldLegend>地址信息</FieldLegend><FieldDescription>我们需要地址来配送订单。</FieldDescription><FieldGroup>
      <Field>
        <FieldLabel for="street">
          街道地址
        </FieldLabel><Input id="street" placeholder="中山路 123 号" />
      </Field>
      <div class="grid grid-cols-2 gap-4">
        <Field>
          <FieldLabel for="city">
            城市
          </FieldLabel><Input id="city" placeholder="上海" />
        </Field><Field>
          <FieldLabel for="postal">
            邮编
          </FieldLabel><Input id="postal" placeholder="200000" />
        </Field>
      </div>
    </FieldGroup>
  </FieldSet>
</template>

复选框

多个复选字段共享说明和图例。

桌面项目

选择要显示的项目。

<script setup lang="ts">
  import { ref } from 'vue'
  import {
    Checkbox,
    Field,
    FieldDescription,
    FieldGroup,
    FieldLabel,
    FieldLegend,
    FieldSet
  } from 'moriui'

  const items = ref({ disk: true, server: false })
</script>

<template>
  <FieldSet class="w-full max-w-xs">
    <FieldLegend variant="label">
      桌面项目
    </FieldLegend><FieldDescription>选择要显示的项目。</FieldDescription><FieldGroup>
      <Field orientation="horizontal">
        <Checkbox id="disk" v-model="items.disk" /><FieldLabel for="disk">
          硬盘
        </FieldLabel>
      </Field>
      <Field orientation="horizontal">
        <Checkbox id="server" v-model="items.server" /><FieldLabel for="server">
          已连接服务器
        </FieldLabel>
      </Field>
    </FieldGroup>
  </FieldSet>
</template>

单选

RadioGroup 与多个 RadioGroupItem 共享 Field 布局。

订阅方案

年付方案更优惠。

<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 orientation="horizontal">
        <RadioGroupItem id="monthly" value="monthly" /><FieldLabel for="monthly">
          月付(¥68/月)
        </FieldLabel>
      </Field>
      <Field orientation="horizontal">
        <RadioGroupItem id="yearly" value="yearly" /><FieldLabel for="yearly">
          年付(¥680/年)
        </FieldLabel>
      </Field>
    </RadioGroup>
  </FieldSet>
</template>

开关

横向 Field 对齐标签与 Switch。

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

  const enabled = shallowRef(false)
</script>

<template>
  <Field class="w-fit" orientation="horizontal">
    <FieldLabel for="two-factor">
      多因素认证
    </FieldLabel><Switch id="two-factor" v-model="enabled" />
  </Field>
</template>

选择卡片

FieldLabel 包裹完整选择卡片。

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

  const environment = shallowRef('kubernetes')
</script>

<template>
  <FieldSet class="w-full max-w-xs">
    <FieldLegend variant="label">
      计算环境
    </FieldLegend>
    <RadioGroup v-model="environment">
      <FieldLabel for="kubernetes">
        <Field orientation="horizontal">
          <FieldContent><FieldTitle>Kubernetes</FieldTitle><FieldDescription>在 K8s 集群运行工作负载。</FieldDescription></FieldContent><RadioGroupItem id="kubernetes" value="kubernetes" />
        </Field>
      </FieldLabel>
      <FieldLabel for="vm">
        <Field orientation="horizontal">
          <FieldContent><FieldTitle>虚拟机</FieldTitle><FieldDescription>使用独立虚拟机运行任务。</FieldDescription></FieldContent><RadioGroupItem id="vm" value="vm" />
        </Field>
      </FieldLabel>
    </RadioGroup>
  </FieldSet>
</template>

字段组

FieldSeparator 分隔通知类别。

研究或图片生成完成时通知我。

任务状态变化时通知我。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import {
    Checkbox,
    Field,
    FieldDescription,
    FieldGroup,
    FieldLabel,
    FieldSeparator,
    FieldSet
  } from 'moriui'

  const taskEmail = shallowRef(false)
</script>

<template>
  <FieldGroup class="w-full max-w-xs">
    <FieldSet>
      <FieldLabel>长任务</FieldLabel><FieldDescription>研究或图片生成完成时通知我。</FieldDescription><Field orientation="horizontal">
        <Checkbox id="push" disabled :model-value="true" /><FieldLabel for="push">
          推送通知
        </FieldLabel>
      </Field>
    </FieldSet>
    <FieldSeparator />
    <FieldSet>
      <FieldLabel>任务更新</FieldLabel><FieldDescription>任务状态变化时通知我。</FieldDescription><Field orientation="horizontal">
        <Checkbox id="task-email" v-model="taskEmail" /><FieldLabel for="task-email">
          邮件通知
        </FieldLabel>
      </Field>
    </FieldSet>
  </FieldGroup>
</template>

RTL

字段结构继承 RTL 文本方向。

معلومات الدفع

جميع المعاملات آمنة ومشفرة.

<script setup lang="ts">
  import {
    Field,
    FieldDescription,
    FieldGroup,
    FieldLabel,
    FieldLegend,
    FieldSet,
    Input
  } from 'moriui'
</script>

<template>
  <FieldSet dir="rtl" class="w-full max-w-sm">
    <FieldLegend>معلومات الدفع</FieldLegend><FieldDescription>جميع المعاملات آمنة ومشفرة.</FieldDescription><FieldGroup>
      <Field>
        <FieldLabel for="rtl-name">
          الاسم على البطاقة
        </FieldLabel><Input id="rtl-name" dir="rtl" required />
      </Field>
    </FieldGroup>
  </FieldSet>
</template>

响应式

responsive 在容器中调整标签与控件布局。

个人资料

填写你的公开资料。

用于团队协作中的身份识别。

<script setup lang="ts">
  import {
    Button,
    Field,
    FieldContent,
    FieldDescription,
    FieldGroup,
    FieldLabel,
    FieldLegend,
    FieldSet,
    Input
  } from 'moriui'
</script>

<template>
  <form class="w-full max-w-lg">
    <FieldSet>
      <FieldLegend>个人资料</FieldLegend><FieldDescription>填写你的公开资料。</FieldDescription><FieldGroup>
        <Field orientation="responsive">
          <FieldContent>
            <FieldLabel for="profile-name">
              姓名
            </FieldLabel><FieldDescription>用于团队协作中的身份识别。</FieldDescription>
          </FieldContent><Input id="profile-name" required placeholder="林晓" />
        </Field>
        <Field orientation="responsive">
          <Button type="submit">
            提交
          </Button><Button type="button" variant="outline">
            取消
          </Button>
        </Field>
      </FieldGroup>
    </FieldSet>
  </form>
</template>

API

属性 类型 默认值 说明
Field orientation'vertical' | 'horizontal' | 'responsive''vertical'标签、控件和说明的布局方向。
FieldLegend variant'legend' | 'label''legend'语义图例的视觉层级。
FieldError errorsArray<string | { message?: string } | null | undefined>[]去重并渲染一个或多个错误消息。
FieldLabelLabelProps完整透传 MoriUI Label 属性。
classHTMLAttributes["class"]undefined所有 Field 子组件均合并调用方类。

无障碍说明

FieldSet 与 FieldLegend 提供原生字段集语义,Field 输出 role="group",FieldError 输出 role="alert"。Label 的 for 必须指向控件 id;无效控件同时使用 aria-invalid 与可读错误消息。

关联组件