- 手风琴 (Accordion)
- 警告 (Alert)
- 警告对话框 (Alert Dialog)
- 宽高比 (Aspect Ratio)
- 头像 (Avatar)
- 徽章 (Badge)
- 面包屑 (Breadcrumb)
- 按钮 (Button)
- 按钮组 (Button Group)
- 日历 (Calendar)
- 卡片 (Card)
- 轮播图 (Carousel)
- 图表 (Chart)
- 复选框 (Checkbox)
- 折叠面板 (Collapsible)
- 组合框 (Combobox)
- 命令面板 (Command)
- 上下文菜单 (Context Menu)
- 数据表格 (Data Table)
- 日期选择器 (Date Picker)
- 对话框 (Dialog)
- 抽屉 (Drawer)
- 下拉菜单 (Dropdown Menu)
- 空状态 (Empty)
- 字段 (Field)
- 表单 (Form)
- 悬停卡片 (Hover Card)
- 输入框 (Input)
- 输入组 (Input Group)
- 验证码输入 (Input OTP)
- 项 (Item)
- 键盘按键 (Kbd)
- 标签 (Label)
- 菜单栏 (Menubar)
- 原生选择器 (Native Select)
- 导航菜单 (Navigation Menu)
- 数字输入框 (Number Field)
- 分页 (Pagination)
- 引脚输入 (Pin Input)
- 气泡卡片 (Popover)
- 进度条 (Progress)
- 单选框组 (Radio Group)
- 范围日历 (Range Calendar)
- 可调整大小 (Resizable)
- 滚动区域 (Scroll Area)
- 选择器 (Select)
- 分隔线 (Separator)
- 侧边栏抽屉 (Sheet)
- 侧边栏 (Sidebar)
- 骨架屏 (Skeleton)
- 滑块 (Slider)
- 轻量提示 (Sonner)
- 加载动画 (Spinner)
- 步骤条 (Stepper)
- 开关 (Switch)
- 表格 (Table)
- 标签页 (Tabs)
- 标签输入 (Tags Input)
- 文本域 (Textarea)
- 吐司提示 (Toast)
- 切换按钮 (Toggle)
- 切换按钮组 (Toggle Group)
- 工具提示 (Tooltip)
- 排版 (Typography)
<script setup lang="ts">
import { ArrowUpIcon, CheckIcon, InfoIcon, PlusIcon, Search } from 'lucide-vue-next'
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea } from '@/components/ui/input-group'
import { Separator } from '@/components/ui/separator'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
</script>
<template>
<div class="grid w-full max-w-sm gap-6">
<InputGroup>
<InputGroupInput placeholder="Search..." />
<InputGroupAddon>
<Search />
</InputGroupAddon>
<InputGroupAddon align="inline-end">
12 results
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="example.com" class="!pl-1" />
<InputGroupAddon>
<InputGroupText>https://</InputGroupText>
</InputGroupAddon>
<InputGroupAddon align="inline-end">
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<InputGroupButton class="rounded-full" size="icon-xs">
<InfoIcon class="size-4" />
</InputGroupButton>
</TooltipTrigger>
<TooltipContent>This is content in a tooltip.</TooltipContent>
</Tooltip>
</TooltipProvider>
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupTextarea placeholder="Ask, Search or Chat..." />
<InputGroupAddon align="block-end">
<InputGroupButton
variant="outline"
class="rounded-full"
size="icon-xs"
>
<PlusIcon class="size-4" />
</InputGroupButton>
<DropdownMenu>
<DropdownMenuTrigger as-child>
<InputGroupButton variant="ghost">
Auto
</InputGroupButton>
</DropdownMenuTrigger>
<DropdownMenuContent
side="top"
align="start"
class="[--radius:0.95rem]"
>
<DropdownMenuItem>Auto</DropdownMenuItem>
<DropdownMenuItem>Agent</DropdownMenuItem>
<DropdownMenuItem>Manual</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<InputGroupText class="ml-auto">
52% used
</InputGroupText>
<Separator orientation="vertical" class="!h-4" />
<InputGroupButton
variant="default"
class="rounded-full"
size="icon-xs"
disabled
>
<ArrowUpIcon class="size-4" />
<span class="sr-only">Send</span>
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="@shadcn" />
<InputGroupAddon align="inline-end">
<div class="flex items-center justify-center rounded-full bg-primary text-primary-foreground size-4">
<CheckIcon class="size-3" />
</div>
</InputGroupAddon>
</InputGroup>
</div>
</template>安装
pnpm dlx shadcn-vue@latest add input-group
使用方法
<script setup lang="ts">
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
InputGroupText,
InputGroupTextarea,
} from '@/components/ui/input-group'
</script>
<template>
<InputGroup>
<InputGroupInput placeholder="Search..." />
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
<InputGroupAddon align="inline-end">
<InputGroupButton>Search</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</template>示例
图标
<script setup lang="ts">
import { CheckIcon, CreditCardIcon, InfoIcon, MailIcon, SearchIcon, StarIcon } from 'lucide-vue-next'
import { InputGroup, InputGroupAddon, InputGroupInput } from '@/components/ui/input-group'
</script>
<template>
<div class="grid w-full max-w-sm gap-6">
<InputGroup>
<InputGroupInput placeholder="Search..." />
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput type="email" placeholder="Enter your email" />
<InputGroupAddon>
<MailIcon />
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="Card number" />
<InputGroupAddon>
<CreditCardIcon />
</InputGroupAddon>
<InputGroupAddon align="inline-end">
<CheckIcon />
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="Card number" />
<InputGroupAddon align="inline-end">
<StarIcon />
<InfoIcon />
</InputGroupAddon>
</InputGroup>
</div>
</template>文本
在输入框旁显示额外的文本信息。
<script setup lang="ts">
import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, InputGroupTextarea } from '@/components/ui/input-group'
</script>
<template>
<div class="grid w-full max-w-sm gap-6">
<InputGroup>
<InputGroupAddon>
<InputGroupText>$</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="0.00" />
<InputGroupAddon align="inline-end">
<InputGroupText>USD</InputGroupText>
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupAddon>
<InputGroupText>https://</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="example.com" class="!pl-0.5" />
<InputGroupAddon align="inline-end">
<InputGroupText>.com</InputGroupText>
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="Enter your username" />
<InputGroupAddon align="inline-end">
<InputGroupText>@company.com</InputGroupText>
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupTextarea placeholder="Enter your message" />
<InputGroupAddon align="block-end">
<InputGroupText class="text-xs text-muted-foreground">
120 characters left
</InputGroupText>
</InputGroupAddon>
</InputGroup>
</div>
</template>按钮
添加按钮以在输入组内执行操作。
<script setup lang="ts">
import { useClipboard } from '@vueuse/core'
import { CheckIcon, CopyIcon, InfoIcon, StarIcon } from 'lucide-vue-next'
import { ref } from 'vue'
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@/components/ui/input-group'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
const isFavorite = ref(false)
const source = ref('hello')
const { text, copy, copied, isSupported } = useClipboard({ source })
</script>
<template>
<div class="grid w-full max-w-sm gap-6">
<InputGroup>
<InputGroupInput placeholder="https://x.com/shadcn" read-only />
<InputGroupAddon align="inline-end">
<InputGroupButton
aria-label="Copy"
title="Copy"
size="icon-xs"
@click="copy('https://x.com/shadcn')"
>
<CheckIcon v-if="!copied" />
<CopyIcon v-if="copied" />
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
<InputGroup class="[--radius:9999px]">
<Popover>
<PopoverTrigger as-child>
<InputGroupAddon>
<InputGroupButton variant="secondary" size="icon-xs">
<InfoIcon />
</InputGroupButton>
</InputGroupAddon>
</PopoverTrigger>
<PopoverContent
align="start"
class="flex flex-col gap-1 text-sm rounded-xl"
>
<p class="font-medium">
Your connection is not secure.
</p>
<p>You should not enter any sensitive information on this site.</p>
</PopoverContent>
</Popover>
<InputGroupAddon class="text-muted-foreground pl-1.5">
https://
</InputGroupAddon>
<InputGroupInput id="input-secure-19" />
<InputGroupAddon align="inline-end">
<InputGroupButton
size="icon-xs"
@click="isFavorite = !isFavorite"
>
<StarIcon
data-favorite="{isFavorite}"
class="data-[favorite=true]:fill-blue-600 data-[favorite=true]:stroke-blue-600"
/>
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="Type to search..." />
<InputGroupAddon align="inline-end">
<InputGroupButton variant="secondary">
Search
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</div>
</template>提示信息
添加提示信息以提供额外背景或帮助。
<script setup lang="ts">
import { HelpCircle, InfoIcon } from 'lucide-vue-next'
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@/components/ui/input-group'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
</script>
<template>
<div class="grid w-full max-w-sm gap-4">
<InputGroup>
<InputGroupInput placeholder="Enter password" type="password" />
<InputGroupAddon align="inline-end">
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<InputGroupButton
variant="ghost"
aria-label="Info"
size="icon-xs"
>
<InfoIcon />
</InputGroupButton>
</TooltipTrigger>
<TooltipContent>
<p>Password must be at least 8 characters</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="Your email address" />
<InputGroupAddon align="inline-end">
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<InputGroupButton
variant="ghost"
aria-label="Help"
size="icon-xs"
>
<HelpCircle />
</InputGroupButton>
</TooltipTrigger>
<TooltipContent>
<p>We'll use this to send you notifications</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="Enter API key" />
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<InputGroupAddon>
<InputGroupButton
variant="ghost"
aria-label="Help"
size="icon-xs"
>
<HelpCircle />
</InputGroupButton>
</InputGroupAddon>
</TooltipTrigger>
<TooltipContent side="left">
<p>Click for help with API keys</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</InputGroup>
</div>
</template>文本域
输入组也适用于文本域组件。使用 block-start 或 block-end 进行对齐。
<script setup lang="ts">
import { BracesIcon, CopyIcon, CornerDownLeftIcon, RefreshCwIcon } from 'lucide-vue-next'
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupTextarea } from '@/components/ui/input-group'
</script>
<template>
<div class="grid w-full max-w-md gap-4">
<InputGroup>
<InputGroupTextarea
id="textarea-code-32"
placeholder="console.log('Hello, world!');"
class="min-h-[200px]"
/>
<InputGroupAddon align="block-end" class="border-t">
<InputGroupText>Line 1, Column 1</InputGroupText>
<InputGroupButton size="sm" class="ml-auto" variant="default">
Run <CornerDownLeftIcon />
</InputGroupButton>
</InputGroupAddon>
<InputGroupAddon align="block-start" class="border-b">
<InputGroupText class="font-mono font-medium">
<BracesIcon />
script.js
</InputGroupText>
<InputGroupButton class="ml-auto" size="icon-xs">
<RefreshCwIcon />
</InputGroupButton>
<InputGroupButton variant="ghost" size="icon-xs">
<CopyIcon />
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</div>
</template>加载指示器
在处理输入时显示加载指示器。
<script setup lang="ts">
import { LoaderIcon } from 'lucide-vue-next'
import { InputGroup, InputGroupAddon, InputGroupInput, InputGroupText } from '@/components/ui/input-group'
import { Spinner } from '@/components/ui/spinner'
</script>
<template>
<div class="grid w-full max-w-sm gap-4">
<InputGroup data-disabled>
<InputGroupInput placeholder="Searching..." disabled />
<InputGroupAddon align="inline-end">
<Spinner />
</InputGroupAddon>
</InputGroup>
<InputGroup data-disabled>
<InputGroupInput placeholder="Processing..." disabled />
<InputGroupAddon>
<Spinner />
</InputGroupAddon>
</InputGroup>
<InputGroup data-disabled>
<InputGroupInput placeholder="Saving changes..." disabled />
<InputGroupAddon align="inline-end">
<InputGroupText>Saving...</InputGroupText>
<Spinner />
</InputGroupAddon>
</InputGroup>
<InputGroup data-disabled>
<InputGroupInput placeholder="Refreshing data..." disabled />
<InputGroupAddon>
<LoaderIcon class="animate-spin" />
</InputGroupAddon>
<InputGroupAddon align="inline-end">
<InputGroupText class="text-muted-foreground">
Please wait...
</InputGroupText>
</InputGroupAddon>
</InputGroup>
</div>
</template>标签
在输入组内添加标签以提高可访问性。
<script setup lang="ts">
import { InfoIcon } from 'lucide-vue-next'
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@/components/ui/input-group'
import { Label } from '@/components/ui/label'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
</script>
<template>
<div class="grid w-full max-w-sm gap-4">
<InputGroup>
<InputGroupInput id="email" placeholder="shadcn" />
<InputGroupAddon>
<Label for="email">@</Label>
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput id="email-2" placeholder="shadcn@vercel.com" />
<InputGroupAddon align="block-start">
<Label for="email-2" class="text-foreground">
Email
</Label>
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<InputGroupButton
variant="ghost"
aria-label="Help"
class="ml-auto rounded-full"
size="icon-xs"
>
<InfoIcon />
</InputGroupButton>
</TooltipTrigger>
<TooltipContent>
<p>We'll use this to send you notifications</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</InputGroupAddon>
</InputGroup>
</div>
</template>下拉菜单
将输入组与下拉菜单配对以实现复杂交互。
<script setup lang="ts">
import { ChevronDownIcon, MoreHorizontal } from 'lucide-vue-next'
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@/components/ui/input-group'
</script>
<template>
<div class="grid w-full max-w-sm gap-4">
<InputGroup>
<InputGroupInput placeholder="Enter file name" />
<InputGroupAddon align="inline-end">
<DropdownMenu>
<DropdownMenuTrigger as-child>
<InputGroupButton
variant="ghost"
aria-label="More"
size="icon-xs"
>
<MoreHorizontal />
</InputGroupButton>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>Settings</DropdownMenuItem>
<DropdownMenuItem>Copy path</DropdownMenuItem>
<DropdownMenuItem>Open location</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</InputGroupAddon>
</InputGroup>
<InputGroup class="[--radius:1rem]">
<InputGroupInput placeholder="Enter search query" />
<InputGroupAddon align="inline-end">
<DropdownMenu>
<DropdownMenuTrigger as-child>
<InputGroupButton variant="ghost" class="!pr-1.5 text-xs">
Search In... <ChevronDownIcon class="size-3" />
</InputGroupButton>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" class="[--radius:0.95rem]">
<DropdownMenuItem>Documentation</DropdownMenuItem>
<DropdownMenuItem>Blog Posts</DropdownMenuItem>
<DropdownMenuItem>Changelog</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</InputGroupAddon>
</InputGroup>
</div>
</template>按钮组
将输入组与按钮组包裹在一起,以创建前缀和后缀。
<script setup lang="ts">
import { Link2Icon } from 'lucide-vue-next'
import { ButtonGroup, ButtonGroupText } from '@/components/ui/button-group'
import { InputGroup, InputGroupAddon, InputGroupInput } from '@/components/ui/input-group'
import { Label } from '@/components/ui/label'
</script>
<template>
<div class="grid w-full max-w-sm">
<ButtonGroup class="!gap-0">
<ButtonGroupText as-child>
<Label for="url">https://</Label>
</ButtonGroupText>
<InputGroup>
<InputGroupInput id="url" />
<InputGroupAddon align="inline-end">
<Link2Icon />
</InputGroupAddon>
</InputGroup>
<ButtonGroupText>.com</ButtonGroupText>
</ButtonGroup>
</div>
</template>自定义输入
将 data-slot="input-group-control" 属性添加到您的自定义输入框中,以实现自动行为和焦点状态处理。
自定义输入框不会应用任何样式。请使用 class 属性应用您自己的样式。
<script setup lang="ts">
import { InputGroup, InputGroupAddon, InputGroupButton } from '@/components/ui/input-group'
</script>
<template>
<div class="grid w-full max-w-sm gap-6">
<InputGroup>
<textarea
data-slot="input-group-control"
class="flex field-sizing-content min-h-16 w-full resize-none rounded-md bg-transparent px-3 py-2.5 text-base transition-[color,box-shadow] outline-none md:text-sm"
placeholder="Autoresize textarea..."
/>
<InputGroupAddon align="block-end">
<InputGroupButton class="ml-auto" size="sm" variant="default">
Submit
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</div>
</template><script setup lang="ts">
import { InputGroup, InputGroupAddon, InputGroupButton } from '@/components/ui/input-group'
</script>
<template>
<div class="grid w-full max-w-sm gap-6">
<InputGroup>
<textarea
data-slot="input-group-control"
class="flex field-sizing-content min-h-16 w-full resize-none rounded-md bg-transparent px-3 py-2.5 text-base transition-[color,box-shadow] outline-none md:text-sm"
placeholder="Autoresize textarea..."
/>
<InputGroupAddon align="block-end">
<InputGroupButton class="ml-auto" size="sm" variant="default">
Submit
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</div>
</template>API 参考
InputGroup
包裹输入框和附加组件的主组件。
| 属性 | 类型 | 默认 |
|---|---|---|
class | string |
<InputGroup>
<InputGroupInput />
<InputGroupAddon />
</InputGroup>InputGroupAddon
在输入框旁显示图标、文本、按钮或其他内容。
为了正确的焦点导航,InputGroupAddon 组件应放置在输入框之后。设置 align 属性以定位附加组件。
| 属性 | 类型 | 默认 |
|---|---|---|
align | "inline-start" | "inline-end" | "block-start" | "block-end" | "inline-start" |
class | string |
<InputGroupAddon align="inline-end">
<SearchIcon />
</InputGroupAddon>对于 <InputGroupInput />,请使用 inline-start 或 inline-end 对齐。对于 <InputGroupTextarea />,请使用 block-start 或 block-end 对齐。
InputGroupAddon 组件可以包含多个 InputGroupButton 组件和图标。
<InputGroupAddon>
<InputGroupButton>Button</InputGroupButton>
<InputGroupButton>Button</InputGroupButton>
</InputGroupAddon>InputGroupButton
在输入组内显示按钮。
| 属性 | 类型 | 默认 |
|---|---|---|
size | "xs" | "icon-xs" | "sm" | "icon-sm" | "xs" |
variant | "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | "ghost" |
class | string |
<InputGroupButton>
Button
</InputGroupButton>
<InputGroupButton size="icon-xs" aria-label="Copy">
<CopyIcon />
</InputGroupButton>InputGroupInput
在构建输入组时,用于替代 <Input />。该组件预置了输入组样式,并使用统一的 data-slot="input-group-control" 进行焦点状态处理。
| 属性 | 类型 | 默认 |
|---|---|---|
class | string |
所有其他属性都会透传至底层的 <Input /> 组件。
<InputGroup>
<InputGroupInput placeholder="Enter text..." />
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
</InputGroup>InputGroupTextarea
在构建输入组时,用于替代 <Textarea />。该组件预置了文本域组样式,并使用统一的 data-slot="input-group-control" 进行焦点状态处理。
| 属性 | 类型 | 默认 |
|---|---|---|
class | string |
所有其他属性都会透传至底层的 <Textarea /> 组件。
<InputGroup>
<InputGroupTextarea placeholder="Enter message..." />
<InputGroupAddon align="block-end">
<InputGroupButton>Send</InputGroupButton>
</InputGroupAddon>
</InputGroup>