组件
- 手风琴 (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 { ArchiveIcon, ArrowLeftIcon, CalendarPlusIcon, ClockIcon, ListFilterPlusIcon, MailCheckIcon, MoreHorizontalIcon, TagIcon, Trash2Icon } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { ButtonGroup } from '@/components/ui/button-group'
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
const label = ref('personal')
</script>
<template>
<ButtonGroup>
<ButtonGroup class="hidden sm:flex">
<Button variant="outline" size="icon" aria-label="Go Back">
<ArrowLeftIcon />
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline">
Archive
</Button>
<Button variant="outline">
Report
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline">
Snooze
</Button>
<DropdownMenu>
<DropdownMenuTrigger as-child>
<Button variant="outline" size="icon" aria-label="More Options">
<MoreHorizontalIcon />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" class="w-52">
<DropdownMenuGroup>
<DropdownMenuItem>
<MailCheckIcon />
Mark as Read
</DropdownMenuItem>
<DropdownMenuItem>
<ArchiveIcon />
Archive
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<ClockIcon />
Snooze
</DropdownMenuItem>
<DropdownMenuItem>
<CalendarPlusIcon />
Add to Calendar
</DropdownMenuItem>
<DropdownMenuItem>
<ListFilterPlusIcon />
Add to List
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<TagIcon class="mr-2 size-4" />
Label As...
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuRadioGroup v-model="label">
<DropdownMenuRadioItem value="personal">
Personal
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="work">
Work
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="other">
Other
</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuSubContent>
</DropdownMenuSub>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive">
<Trash2Icon />
Trash
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</ButtonGroup>
</ButtonGroup>
</template>安装
pnpm dlx shadcn-vue@latest add button-group
使用方法
<script setup lang="ts">
import {
ButtonGroup,
ButtonGroupSeparator,
ButtonGroupText,
} from '@/components/ui/button-group'
</script>
<template>
<ButtonGroup>
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>
</template>无障碍
ButtonGroup组件的role属性被设置为group。- 使用
Tab键在组内的按钮之间进行导航。 - 使用
aria-label或aria-labelledby来标注按钮组。
<template>
<ButtonGroup aria-label="Button group">
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>
</template>ButtonGroup 与 ToggleGroup 的区别
- 当您需要将执行操作的按钮组合在一起时,请使用
ButtonGroup组件。 - 当您需要将切换状态的按钮组合在一起时,请使用
ToggleGroup组件。
示例
方向
设置 orientation 属性以更改按钮组的布局。
<script setup lang="ts">
import { MinusIcon, PlusIcon } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { ButtonGroup } from '@/components/ui/button-group'
</script>
<template>
<ButtonGroup
orientation="vertical"
aria-label="Media controls"
class="h-fit"
>
<Button variant="outline" size="icon">
<PlusIcon />
</Button>
<Button variant="outline" size="icon">
<MinusIcon />
</Button>
</ButtonGroup>
</template>尺寸
通过在单个按钮上使用 size 属性来控制按钮的尺寸。
<script setup lang="ts">
import { PlusIcon } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { ButtonGroup } from '@/components/ui/button-group'
</script>
<template>
<div class="flex flex-col items-start gap-8">
<ButtonGroup>
<Button variant="outline" size="sm">
Small
</Button>
<Button variant="outline" size="sm">
Button
</Button>
<Button variant="outline" size="sm">
Group
</Button>
<Button variant="outline" size="icon-sm">
<PlusIcon />
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline">
Default
</Button>
<Button variant="outline">
Button
</Button>
<Button variant="outline">
Group
</Button>
<Button variant="outline">
<PlusIcon />
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline" size="lg">
Large
</Button>
<Button variant="outline" size="lg">
Button
</Button>
<Button variant="outline" size="lg">
Group
</Button>
<Button variant="outline" size="icon-lg">
<PlusIcon />
</Button>
</ButtonGroup>
</div>
</template>嵌套
使用 <ButtonGroup> 组件来创建带有间距的按钮组。
<script setup lang="ts">
import { ArrowLeftIcon, ArrowRightIcon } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { ButtonGroup } from '@/components/ui/button-group'
</script>
<template>
<ButtonGroup>
<ButtonGroup>
<Button variant="outline" size="sm">
1
</Button>
<Button variant="outline" size="sm">
2
</Button>
<Button variant="outline" size="sm">
3
</Button>
<Button variant="outline" size="sm">
4
</Button>
<Button variant="outline" size="sm">
5
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline" size="icon-sm" aria-label="Previous">
<ArrowLeftIcon />
</Button>
<Button variant="outline" size="icon-sm" aria-label="Next">
<ArrowRightIcon />
</Button>
</ButtonGroup>
</ButtonGroup>
</template>分隔符
ButtonGroupSeparator 组件用于在视觉上分隔组内的按钮。
变体为 outline 的按钮不需要分隔符,因为它们自带边框。对于其他变体,建议使用分隔符以改善视觉层次结构。
<script setup lang="ts">
import { Button } from '@/components/ui/button'
import { ButtonGroup, ButtonGroupSeparator } from '@/components/ui/button-group'
</script>
<template>
<ButtonGroup>
<Button variant="secondary" size="sm">
Copy
</Button>
<ButtonGroupSeparator />
<Button variant="secondary" size="sm">
Paste
</Button>
</ButtonGroup>
</template>拆分
通过添加两个由 ButtonGroupSeparator 分隔的按钮来创建拆分按钮组。
<script setup lang="ts">
import { PlusIcon } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { ButtonGroup, ButtonGroupSeparator } from '@/components/ui/button-group'
</script>
<template>
<ButtonGroup>
<Button variant="secondary">
Button
</Button>
<ButtonGroupSeparator />
<Button size="icon" variant="secondary">
<PlusIcon />
</Button>
</ButtonGroup>
</template>输入框
将 Input 组件与按钮进行封装。
<script setup lang="ts">
import { SearchIcon } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { ButtonGroup } from '@/components/ui/button-group'
import { Input } from '@/components/ui/input'
</script>
<template>
<ButtonGroup>
<Input placeholder="Search..." />
<Button variant="outline" aria-label="Search">
<SearchIcon />
</Button>
</ButtonGroup>
</template>输入组
封装 InputGroup 组件以创建复杂的输入布局。
<script setup lang="ts">
import { AudioLinesIcon, PlusIcon } from 'lucide-vue-next'
import { ref } from 'vue'
import { Button } from '@/components/ui/button'
import { ButtonGroup } from '@/components/ui/button-group'
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@/components/ui/input-group'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
const voiceEnabled = ref(false)
</script>
<template>
<ButtonGroup class="[--radius:9999rem]">
<ButtonGroup>
<Button variant="outline" size="icon" aria-label="Add">
<PlusIcon />
</Button>
</ButtonGroup>
<ButtonGroup class="flex-1">
<InputGroup>
<InputGroupInput
:placeholder="voiceEnabled ? 'Record and send audio...' : 'Send a message...'"
:disabled="voiceEnabled"
/>
<InputGroupAddon align="inline-end">
<TooltipProvider>
<Tooltip>
<TooltipTrigger as-child>
<InputGroupButton
:data-active="voiceEnabled"
class="data-[active=true]:bg-orange-100 data-[active=true]:text-orange-700 dark:data-[active=true]:bg-orange-800 dark:data-[active=true]:text-orange-100"
:aria-pressed="voiceEnabled"
size="icon-xs"
aria-label="Voice Mode"
@click="() => voiceEnabled = !voiceEnabled"
>
<AudioLinesIcon />
</InputGroupButton>
</TooltipTrigger>
<TooltipContent>Voice Mode</TooltipContent>
</Tooltip>
</TooltipProvider>
</InputGroupAddon>
</InputGroup>
</ButtonGroup>
</ButtonGroup>
</template>下拉菜单
使用 DropdownMenu 组件创建拆分按钮组。
<script setup lang="ts">
import { AlertTriangleIcon, CheckIcon, ChevronDownIcon, CopyIcon, ShareIcon, TrashIcon, UserRoundXIcon, VolumeOffIcon } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { ButtonGroup } from '@/components/ui/button-group'
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
</script>
<template>
<ButtonGroup>
<Button variant="outline">
Follow
</Button>
<DropdownMenu>
<DropdownMenuTrigger as-child>
<Button variant="outline" size="icon">
<ChevronDownIcon />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" class="[--radius:1rem]">
<DropdownMenuGroup>
<DropdownMenuItem>
<VolumeOffIcon />
Mute Conversation
</DropdownMenuItem>
<DropdownMenuItem>
<CheckIcon />
Mark as Read
</DropdownMenuItem>
<DropdownMenuItem>
<AlertTriangleIcon />
Report Conversation
</DropdownMenuItem>
<DropdownMenuItem>
<UserRoundXIcon />
Block User
</DropdownMenuItem>
<DropdownMenuItem>
<ShareIcon />
Share Conversation
</DropdownMenuItem>
<DropdownMenuItem>
<CopyIcon />
Copy Conversation
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive">
<TrashIcon />
Delete Conversation
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</ButtonGroup>
</template>选择
与 Select 组件搭配使用。
<script setup lang="ts">
import { ArrowRightIcon } from 'lucide-vue-next'
import { ref } from 'vue'
import { Button } from '@/components/ui/button'
import { ButtonGroup } from '@/components/ui/button-group'
import { Input } from '@/components/ui/input'
import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select'
const CURRENCIES = [
{
value: '$',
label: 'US Dollar',
},
{
value: '€',
label: 'Euro',
},
{
value: '£',
label: 'British Pound',
},
]
const currency = ref('$')
</script>
<template>
<ButtonGroup>
<ButtonGroup>
<Select v-model="currency">
<SelectTrigger class="font-mono w-14">
{{ currency }}
</SelectTrigger>
<SelectContent class="min-w-24">
<SelectItem v-for="item in CURRENCIES" :key="item.value" :value="item.value">
{{ item.value }}
<span class="text-muted-foreground">{{ item.label }}</span>
</SelectItem>
</SelectContent>
</Select>
<Input placeholder="10.00" pattern="[0-9]*" />
</ButtonGroup>
<ButtonGroup>
<Button aria-label="Send" size="icon" variant="outline">
<ArrowRightIcon />
</Button>
</ButtonGroup>
</ButtonGroup>
</template>气泡卡片
与 Popover 组件搭配使用。
<script setup lang="ts">
import { BotIcon, ChevronDownIcon } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { ButtonGroup } from '@/components/ui/button-group'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/components/ui/popover'
import { Separator } from '@/components/ui/separator'
import { Textarea } from '@/components/ui/textarea'
</script>
<template>
<ButtonGroup>
<Button variant="outline">
<BotIcon /> Copilot
</Button>
<Popover>
<PopoverTrigger as-child>
<Button variant="outline" size="icon" aria-label="Open Popover">
<ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent align="end" class="p-0 text-sm rounded-xl">
<div class="px-4 py-3">
<div class="text-sm font-medium">
Agent Tasks
</div>
</div>
<Separator />
<div class="p-4 text-sm *:[p:not(:last-child)]:mb-2">
<Textarea
placeholder="Describe your task in natural language."
class="mb-4 resize-none"
/>
<p class="font-medium">
Start a new task with Copilot
</p>
<p class="text-muted-foreground">
Describe your task in natural language. Copilot will work in the
background and open a pull request for your review.
</p>
</div>
</PopoverContent>
</Popover>
</ButtonGroup>
</template>API 参考
ButtonGroup
ButtonGroup 组件是一个将相关按钮组合在一起并保持样式统一的容器。
| 属性 | 类型 | 默认 |
|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" |
<template>
<ButtonGroup>
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>
</template>嵌套多个按钮组以创建带有间距的复杂布局。详情请参阅 嵌套 示例。
<template>
<ButtonGroup>
<ButtonGroup />
<ButtonGroup />
</ButtonGroup>
</template>ButtonGroupSeparator
ButtonGroupSeparator 组件用于在视觉上分隔组内的按钮。
| 属性 | 类型 | 默认 |
|---|---|---|
orientation | "horizontal" | "vertical" | vertical |
<template>
<ButtonGroup>
<Button>Button 1</Button>
<ButtonGroupSeparator />
<Button>Button 2</Button>
</ButtonGroup>
</template>ButtonGroupText
使用此组件在按钮组内显示文本。
| 属性 | 类型 | 默认 |
|---|---|---|
as-child | boolean | false |
<template>
<ButtonGroup>
<ButtonGroupText>Text</ButtonGroupText>
<Button>Button</Button>
</ButtonGroup>
</template>使用 as-child 属性将自定义组件(例如 label)渲染为文本。
<script setup lang="ts">
import { ButtonGroupText } from '@/components/ui/button-group'
import { Label } from '@/components/ui/label'
</script>
<template>
<ButtonGroup>
<ButtonGroupText as-child>
<Label for="name">Text</Label>
</ButtonGroupText>
<Input id="name" placeholder="Type something here..." />
</ButtonGroup>
</template>