表单

Input Group 输入组合

用于输入组合场景的 MoriUI 组件。

资源

导入

import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText } from 'moriui'

组合方式

InputGroup 组合 InputGroupInput、Addon、Button 与 Text;MoriUI 当前不导出 InputGroupTextarea。

附加内容对齐

Addon align 支持 inline-start、inline-end、block-start 与 block-end;DOM 中应放在控件之后,以保持焦点导航。

自定义控件

MoriUI Textarea 等控件可作为 InputGroup 的自定义控制区,并与块级附加内容共同布局。

RTL

inline-start 和 inline-end 是逻辑方向,在 RTL 中自然翻转。

示例

概览

搜索图标、输入和结果数量共享边界。

12 个结果
<script setup lang="ts">
  import { shallowRef } from 'vue'
  import { Search } from '@lucide/vue'
  import { InputGroup, InputGroupAddon, InputGroupInput } from 'moriui'

  const query = shallowRef('')
</script>

<template>
  <InputGroup class="w-full max-w-xs">
    <InputGroupInput v-model="query" aria-label="搜索" placeholder="搜索…" /><InputGroupAddon><Search /></InputGroupAddon><InputGroupAddon align="inline-end">
      12 个结果
    </InputGroupAddon>
  </InputGroup>
</template>

行内起始

图标位于逻辑起始侧。

图标位于输入框起始侧。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import { Search } from '@lucide/vue'
  import {
    Field,
    FieldDescription,
    FieldLabel,
    InputGroup,
    InputGroupAddon,
    InputGroupInput
  } from 'moriui'

  const query = shallowRef('')
</script>

<template>
  <Field class="w-full max-w-sm">
    <FieldLabel for="inline-start">
      搜索
    </FieldLabel><InputGroup>
      <InputGroupInput id="inline-start" v-model="query" /><InputGroupAddon align="inline-start">
        <Search />
      </InputGroupAddon>
    </InputGroup><FieldDescription>图标位于输入框起始侧。</FieldDescription>
  </Field>
</template>

行内结束

操作位于逻辑结束侧。

图标位于输入框结束侧。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import { EyeOff } from '@lucide/vue'
  import {
    Field,
    FieldDescription,
    FieldLabel,
    InputGroup,
    InputGroupAddon,
    InputGroupInput
  } from 'moriui'

  const password = shallowRef('')
</script>

<template>
  <Field class="w-full max-w-sm">
    <FieldLabel for="inline-end">
      密码
    </FieldLabel><InputGroup>
      <InputGroupInput id="inline-end" v-model="password" type="password" /><InputGroupAddon align="inline-end">
        <EyeOff />
      </InputGroupAddon>
    </InputGroup><FieldDescription>图标位于输入框结束侧。</FieldDescription>
  </Field>
</template>

块级起始

标题附加内容位于控件上方。

完整姓名

附加内容位于输入框上方。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import {
    Field,
    FieldDescription,
    FieldLabel,
    InputGroup,
    InputGroupAddon,
    InputGroupInput,
    InputGroupText
  } from 'moriui'

  const name = shallowRef('')
</script>

<template>
  <Field class="w-full max-w-sm">
    <FieldLabel for="block-start">
      姓名
    </FieldLabel><InputGroup>
      <InputGroupInput id="block-start" v-model="name" placeholder="输入姓名" /><InputGroupAddon align="block-start">
        <InputGroupText>完整姓名</InputGroupText>
      </InputGroupAddon>
    </InputGroup><FieldDescription>附加内容位于输入框上方。</FieldDescription>
  </Field>
</template>

块级结束

辅助内容位于控件下方。

人民币 CNY

附加内容位于输入框下方。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import {
    Field,
    FieldDescription,
    FieldLabel,
    InputGroup,
    InputGroupAddon,
    InputGroupInput,
    InputGroupText
  } from 'moriui'

  const amount = shallowRef('')
</script>

<template>
  <Field class="w-full max-w-sm">
    <FieldLabel for="block-end">
      金额
    </FieldLabel><InputGroup>
      <InputGroupInput id="block-end" v-model="amount" inputmode="decimal" /><InputGroupAddon align="block-end">
        <InputGroupText>人民币 CNY</InputGroupText>
      </InputGroupAddon>
    </InputGroup><FieldDescription>附加内容位于输入框下方。</FieldDescription>
  </Field>
</template>

图标

组合起始与结束图标。

<script setup lang="ts">
  import { Check, CreditCard, Mail, Search } from '@lucide/vue'
  import { InputGroup, InputGroupAddon, InputGroupInput } from 'moriui'
</script>

<template>
  <div class="grid w-full max-w-sm gap-4">
    <InputGroup><InputGroupInput aria-label="搜索" placeholder="搜索…" /><InputGroupAddon><Search /></InputGroupAddon></InputGroup><InputGroup><InputGroupInput aria-label="邮箱" type="email" placeholder="输入邮箱" /><InputGroupAddon><Mail /></InputGroupAddon></InputGroup><InputGroup>
      <InputGroupInput aria-label="卡号" placeholder="卡号" /><InputGroupAddon><CreditCard /></InputGroupAddon><InputGroupAddon align="inline-end">
        <Check />
      </InputGroupAddon>
    </InputGroup>
  </div>
</template>

文字

货币、协议和单位作为附加文字。

¥
CNY
https://
<script setup lang="ts">
  import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText } from 'moriui'
</script>

<template>
  <div class="grid w-full max-w-sm gap-4">
    <InputGroup>
      <InputGroupAddon><InputGroupText>¥</InputGroupText></InputGroupAddon><InputGroupInput aria-label="金额" placeholder="0.00" /><InputGroupAddon align="inline-end">
        <InputGroupText>CNY</InputGroupText>
      </InputGroupAddon>
    </InputGroup><InputGroup><InputGroupAddon><InputGroupText>https://</InputGroupText></InputGroupAddon><InputGroupInput aria-label="域名" placeholder="example.com" /></InputGroup>
  </div>
</template>

按钮

复制、收藏等操作位于输入边界内。

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import { Check, Copy, Star } from '@lucide/vue'
  import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from 'moriui'

  const copied = shallowRef(false)
  const favorite = shallowRef(false)
</script>

<template>
  <div class="grid w-full max-w-sm gap-4">
    <InputGroup>
      <InputGroupInput model-value="https://moriui.dev" readonly /><InputGroupAddon align="inline-end">
        <InputGroupButton size="icon-xs" aria-label="复制" @click="copied = true">
          <Check v-if="copied" /><Copy v-else />
        </InputGroupButton>
      </InputGroupAddon>
    </InputGroup><InputGroup>
      <InputGroupInput aria-label="页面地址" /><InputGroupAddon align="inline-end">
        <InputGroupButton
          size="icon-xs"
          :aria-pressed="favorite"
          aria-label="收藏"
          @click="favorite = !favorite"
        >
          <Star :class="{ 'fill-current': favorite }" />
        </InputGroupButton>
      </InputGroupAddon>
    </InputGroup>
  </div>
</template>

快捷键

Kbd 提示全局搜索快捷键。

⌘K
<script setup lang="ts">
  import { Search } from '@lucide/vue'
  import { InputGroup, InputGroupAddon, InputGroupInput, Kbd } from 'moriui'
</script>

<template>
  <InputGroup class="w-full max-w-sm">
    <InputGroupInput aria-label="全局搜索" placeholder="搜索…" /><InputGroupAddon><Search /></InputGroupAddon><InputGroupAddon align="inline-end">
      <Kbd>⌘K</Kbd>
    </InputGroupAddon>
  </InputGroup>
</template>

菜单入口

紧凑按钮提供更多选择入口。

<script setup lang="ts">
  import { ChevronDown, MoreHorizontal } from '@lucide/vue'
  import {
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuItem,
    DropdownMenuTrigger,
    InputGroup,
    InputGroupAddon,
    InputGroupButton,
    InputGroupInput
  } from 'moriui'
</script>

<template>
  <div class="grid w-full max-w-sm gap-4">
    <InputGroup>
      <InputGroupInput aria-label="文件名" placeholder="输入文件名" /><InputGroupAddon align="inline-end">
        <DropdownMenu>
          <DropdownMenuTrigger as-child>
            <InputGroupButton size="icon-xs" aria-label="文件操作">
              <MoreHorizontal />
            </InputGroupButton>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end">
            <DropdownMenuItem>重命名</DropdownMenuItem>
            <DropdownMenuItem>清空</DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
      </InputGroupAddon>
    </InputGroup><InputGroup>
      <InputGroupInput aria-label="搜索词" placeholder="搜索…" /><InputGroupAddon align="inline-end">
        <DropdownMenu>
          <DropdownMenuTrigger as-child>
            <InputGroupButton>文档<ChevronDown /></InputGroupButton>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end">
            <DropdownMenuItem>文档</DropdownMenuItem>
            <DropdownMenuItem>代码</DropdownMenuItem>
            <DropdownMenuItem>全部内容</DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
      </InputGroupAddon>
    </InputGroup>
  </div>
</template>

加载状态

Spinner 与状态文字表达进行中任务。

保存中
<script setup lang="ts">
  import { LoaderCircle } from '@lucide/vue'
  import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, Spinner } from 'moriui'
</script>

<template>
  <div class="grid w-full max-w-sm gap-4">
    <InputGroup>
      <InputGroupInput aria-label="搜索状态" placeholder="搜索中…" /><InputGroupAddon align="inline-end">
        <Spinner />
      </InputGroupAddon>
    </InputGroup><InputGroup>
      <InputGroupInput aria-label="保存状态" placeholder="保存更改…" /><InputGroupAddon align="inline-end">
        <InputGroupText>保存中</InputGroupText><LoaderCircle class="animate-spin" />
      </InputGroupAddon>
    </InputGroup>
  </div>
</template>

多行输入

MoriUI Textarea 与块级 Addon 组成多行编辑器。

script.js
第 1 行
<script setup lang="ts">
  import { Copy, Play } from '@lucide/vue'
  import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, Textarea } from 'moriui'
</script>

<template>
  <InputGroup class="w-full max-w-md">
    <Textarea
      data-slot="input-group-control"
      class="min-h-40 resize-none"
      aria-label="代码"
      placeholder="console.log('你好,MoriUI')"
    /><InputGroupAddon align="block-start">
      <InputGroupText>script.js</InputGroupText><InputGroupButton class="ms-auto" size="icon-xs" aria-label="复制">
        <Copy />
      </InputGroupButton>
    </InputGroupAddon><InputGroupAddon align="block-end">
      <InputGroupText>第 1 行</InputGroupText><InputGroupButton class="ms-auto" variant="default">
        <Play />运行
      </InputGroupButton>
    </InputGroupAddon>
  </InputGroup>
</template>

自定义控件

自定义自动增高 textarea 保持统一焦点处理。

<script setup lang="ts">
  import { InputGroup, InputGroupAddon, InputGroupButton, Textarea } from 'moriui'
</script>

<template>
  <InputGroup class="w-full max-w-sm">
    <Textarea
      data-slot="input-group-control"
      class="field-sizing-content min-h-16 resize-none"
      aria-label="自动增高文本"
      placeholder="输入多行内容…"
    /><InputGroupAddon align="block-end">
      <InputGroupButton class="ms-auto" variant="default">
        提交
      </InputGroupButton>
    </InputGroupAddon>
  </InputGroup>
</template>

RTL

逻辑对齐在 RTL 中保持自然顺序。

١٢ نتيجة
جاري الحفظ
<script setup lang="ts">
  import { Search } from '@lucide/vue'
  import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, Spinner } from 'moriui'
</script>

<template>
  <div dir="rtl" class="grid w-full max-w-sm gap-4">
    <InputGroup>
      <InputGroupInput dir="rtl" aria-label="بحث" placeholder="بحث…" /><InputGroupAddon><Search /></InputGroupAddon><InputGroupAddon align="inline-end">
        ١٢ نتيجة
      </InputGroupAddon>
    </InputGroup><InputGroup>
      <InputGroupInput dir="rtl" aria-label="حالة الحفظ" placeholder="جاري حفظ التغييرات…" /><InputGroupAddon align="inline-end">
        <InputGroupText>جاري الحفظ</InputGroupText><Spinner />
      </InputGroupAddon>
    </InputGroup>
  </div>
</template>

API

属性 类型 默认值 说明
InputGroup classHTMLAttributes["class"]undefined合并到 role="group" 根容器。
InputGroupAddon align'inline-start' | 'inline-end' | 'block-start' | 'block-end''inline-start'附加内容的逻辑位置。
InputGroupInput v-modelstring''输入组合中的受控字符串值。
InputGroupInput defaultValuestringundefined非受控初始值。
InputGroupButton variantButtonVariants["variant"]'ghost'内嵌按钮视觉层级。
InputGroupButton size'xs' | 'sm' | 'icon-xs' | 'icon-sm''xs'内嵌按钮尺寸。

无障碍说明

InputGroup 不替代输入标签,仍需 FieldLabel 或 aria-label。Addon 应在 DOM 中位于控件之后;点击非交互附加内容会聚焦 data-slot="input-group-control",按钮、链接等交互元素保持独立焦点。

关联组件