ColorChooser
简介
MColorChooser 是一个可视化的颜色选择器组件。提供色盘与 HSL 滑块取色,支持自定义触发器形态、预设色板、复制与清除,并将值同步为 hex、rgb 或 hsl 三种格式之一。
用法
默认按钮触发器展示当前色值,点击打开 popover 后从面板选择并同步 v-model:
<script setup lang="ts">
const value = ref("#0ea5e9")
</script>
<template>
<MColorChooser v-model="value" />
</template>
formats 输出格式
在 popover 顶部切换 hex、rgb、hsl 、cmyk、lab,当前值会转换为对应格式:
<script setup lang="ts">
const value = ref('#22c55e')
</script>
<template>
<MColorChooser v-model="value" :formats="['hex', 'rgb', 'hsl', 'cmyk', 'lab']" />
</template>
swatches 单组预设
一维 swatches 渲染为连续色板,点击色块选中颜色并默认关闭弹层:
<script setup lang="ts">
const value = ref('#ef4444')
</script>
<template>
<MColorChooser
v-model="value"
:swatches="[
'#ef4444',
'#f97316',
'#f59e0b',
'#eab308',
'#84cc16',
'#22c55e',
'#10b981',
'#14b8a6',
'#06b6d4',
'#0ea5e9',
'#3b82f6',
'#6366f1',
'#8b5cf6',
'#a855f7',
'#d946ef',
'#ec4899'
]"
/>
</template>
swatches 分组预设
二维 swatches 按行分组展示色相与中性色,closeOnSwatch 控制选择后是否关闭:
<script setup lang="ts">
const value = ref('#3b82f6')
</script>
<template>
<MColorChooser
v-model="value"
:close-on-swatch="false"
:swatches="[
['#ef4444', '#f97316', '#f59e0b', '#eab308', '#84cc16', '#22c55e', '#10b981', '#14b8a6'],
['#06b6d4', '#0ea5e9', '#3b82f6', '#6366f1', '#8b5cf6', '#a855f7', '#d946ef', '#ec4899'],
['#0a0a0a', '#404040', '#737373', '#a3a3a3', '#d4d4d4', '#e5e5e5', '#f5f5f5', '#ffffff']
]"
/>
</template>
trigger 触发器
trigger 控制触发器形态:button 渲染按钮,chip 仅渲染紧凑色块,input 提供色点 + 文本输入并在 blur 时校验 hex:
<script setup lang="ts">
const value = ref("#f59e0b")
</script>
<template>
<MColorChooser v-model="value" trigger="chip" />
</template>
copyable 复制按钮
copyable 启用 popover 底部的复制按钮,点击触发 @copy 事件:
<script setup lang="ts">
const value = ref("#a855f7")
</script>
<template>
<MColorChooser v-model="value" copyable />
</template>
clearable 清除按钮
clearable 启用 popover 底部的清除按钮,点击重置当前值并触发 @clear 事件:
<script setup lang="ts">
const value = ref("#a855f7")
</script>
<template>
<MColorChooser v-model="value" clearable />
</template>
ui 样式定制
ui 覆盖内部 slot 的 class,可定制色板网格与色块尺寸,不影响取色、复制和清除机制:
<script setup lang="ts">
const value = ref('#14b8a6')
</script>
<template>
<MColorChooser
v-model="value"
:ui="{
swatches: 'grid grid-cols-4 gap-2',
swatch: 'size-8 rounded-lg ring-2 ring-default cursor-pointer hover:ring-primary'
}"
:swatches="[
'#ef4444',
'#f97316',
'#f59e0b',
'#eab308',
'#84cc16',
'#22c55e',
'#10b981',
'#14b8a6',
'#06b6d4',
'#0ea5e9',
'#3b82f6',
'#6366f1',
'#8b5cf6',
'#a855f7',
'#d946ef',
'#ec4899'
]"
/>
</template>
disabled 禁用状态
disabled 阻止 popover 打开,input 触发器进入只读状态,当前值保持可展示:
<script setup lang="ts">
const value = ref("#6b7280")
</script>
<template>
<MColorChooser v-model="value" disabled />
</template>
示例
继承字段上下文
放入 UFormField 后继承 size 与错误态,触发器按表单状态渲染:
<template>
<UFormField label="品牌色" size="xs" error="示例错误态">
<MColorChooser />
</UFormField>
</template>
融入UFieldGroup
与按钮置于 UFieldGroup 时共用尺寸、圆角和边框衔接,适合表单行内取色:
<template>
<UFieldGroup size="xs">
<MColorChooser trigger="input" />
<UButton icon="i-lucide-pipette" color="neutral" variant="subtle" />
</UFieldGroup>
</template>
自定义触发器渲染
default 插槽可完全接管触发器外观,同时通过 open 与 value slot props 保持弹层状态可见:
<script setup lang="ts">
const value = ref('#ec4899')
const tailwindPalette = [
'#ef4444',
'#f97316',
'#f59e0b',
'#eab308',
'#84cc16',
'#22c55e',
'#10b981',
'#14b8a6',
'#06b6d4',
'#0ea5e9',
'#3b82f6',
'#6366f1',
'#8b5cf6',
'#a855f7',
'#d946ef',
'#ec4899'
]
</script>
<template>
<MColorChooser v-model="value" :swatches="tailwindPalette">
<template #default="{ open, value: current }">
<button
type="button"
class="size-12 rounded-xl border-2 border-default cursor-pointer hover:scale-105 transition flex items-center justify-center"
:style="{ backgroundColor: current }"
:aria-expanded="open"
>
<UIcon v-if="!current" name="i-lucide-plus" class="text-muted" />
</button>
</template>
</MColorChooser>
</template>
API
Props
| Prop | Default | Type |
|---|---|---|
id | string | |
name | string | |
format | 'hex' | "hex" | "rgb" | "hsl" | "cmyk" | "lab"当前激活的颜色格式。 |
formats | ["hex"] | ColorFormat[]启用的颜色格式 tab 列表,长度 >= 2 时在 popover 顶部渲染切换器。
仅一项时不渲染 tab,等价于 |
swatches | string[] | string[][]预设色板。 一维数组渲染为单行,二维数组渲染为多行分组。 | |
trigger | 'button' | "button" | "chip" | "input"触发器形态。
|
label | string
| |
placeholder | '选择颜色' | string未选中颜色时的占位文案。 |
size | 'md' | "md" | "xs" | "sm" | "lg" | "xl"触发器尺寸,同时驱动主题 size variant。 |
color | 'neutral' | "primary" | "secondary" | "info" | "success" | "warning" | "error" | "important" | "neutral"触发按钮的颜色(trigger=button|chip 生效)。 |
variant | 'subtle' | "solid" | "outline" | "soft" | "subtle" | "ghost" | "link"触发按钮的视觉变体(trigger=button|chip 生效)。 |
icon | 'i-lucide-palette' | any未选中颜色时占位的图标。 |
colorPickerProps | Omit<ColorPickerProps, "format" | "disabled" | "modelValue">透传给 | |
mode | 'click' | MThe display mode of the popover. |
content | { side: 'bottom', sideOffset: 8, collisionPadding: 8 } | PopoverContentProps & Partial<EmitsToProps<PopoverContentImplEmits>>The content of the popover. |
arrow | false | boolean | PopoverArrowPropsDisplay an arrow alongside the popover.
|
portal | true | string | false | true | HTMLElementRender the popover in a portal. |
reference | Element | VirtualElementThe reference (or anchor) element that is being referred to for positioning. Accepts an element or a virtual element (anything with | |
openDelay | numberThe duration from when the mouse enters the trigger until the hover card opens. | |
closeDelay | numberThe duration from when the mouse leaves the trigger or content until the hover card closes. | |
modelValue | string | |
closeOnSwatch | true | boolean点击预设色后是否自动关闭弹层。 |
clearable | boolean是否在底部 actions 区显示清除按钮。 | |
copyable | booleanactions 区显示复制按钮(基于 navigator.clipboard)。 | |
disabled | boolean是否禁用。禁用时弹层不会打开、所有交互失效。 | |
highlight | booleanHighlight the ring color like a focus state. | |
dismissible | true | booleanWhen |
modal | false | booleanThe modality of the popover. When set to true, interaction with outside elements will be disabled and only popover content will be visible to screen readers. |
ui | Record<string, ClassNameValue> & { content?: SlotClass; arrow?: SlotClass; body?: SlotClass; header?: SlotClass; section?: SlotClass; swatches?: SlotClass; swatch?: SlotClass; actions?: SlotClass; actionsValue?: SlotClass; actionsButtons?: SlotClass; triggerChipWrapper?: SlotClass; triggerChip?: SlotClass; triggerLabel?: SlotClass; triggerIcon?: SlotClass; } |
Emits
| Event | Type |
|---|---|
update:modelValue | [value: string] |
update:open | [open: boolean] |
change | [value: string] |
clear | [] |
copy | [value: string] |
format-change | [format: ColorFormat] |
Slots
| Slot | Type |
|---|---|
default | { open: boolean; value: string; } |
leading | { value: string; } |
trailing | { value: string; } |
swatches | { swatches: string[][]; select: (color: string) => void; } |
actions | { value: string; copy: () => void; clear: () => void; } |
Theme
export default defineAppConfig({
ui: {
colorChooser: {
slots: {
body: 'p-2 flex flex-col gap-2 min-w-[14rem]',
header: 'flex items-center justify-between gap-2',
section: 'flex flex-col gap-1.5',
swatches: 'grid grid-cols-8 gap-1',
swatch: 'rounded ring-1 ring-default cursor-pointer transition hover:scale-110 hover:ring-2 hover:ring-primary aria-selected:ring-2 aria-selected:ring-primary',
actions: 'mt-1 flex items-center justify-between gap-1.5 border-t border-default pt-2',
actionsValue: 'text-xs text-muted tabular-nums truncate',
actionsButtons: 'flex items-center gap-1',
triggerChipWrapper: '',
triggerChip: 'rounded-full ring-1 ring-default shrink-0 transition',
triggerLabel: 'tabular-nums truncate',
triggerIcon: 'text-muted shrink-0'
},
variants: {
size: {
xs: {
triggerChip: 'size-2.5',
swatch: 'size-4',
triggerIcon: 'size-3'
},
sm: {
triggerChip: 'size-3',
swatch: 'size-4',
triggerIcon: 'size-3.5'
},
md: {
triggerChip: 'size-3.5',
swatch: 'size-5',
triggerIcon: 'size-4'
},
lg: {
triggerChip: 'size-4',
swatch: 'size-5',
triggerIcon: 'size-4'
},
xl: {
triggerChip: 'size-5',
swatch: 'size-6',
triggerIcon: 'size-5'
}
},
trigger: {
button: {},
chip: {},
input: {}
},
disabled: {
true: {
body: 'opacity-60 pointer-events-none'
}
}
},
defaultVariants: {
size: 'md',
trigger: 'button'
}
}
}
})