ColorChooser

View source
可视化颜色选择器组件。

简介

MColorChooser 是一个可视化的颜色选择器组件。提供色盘与 HSL 滑块取色,支持自定义触发器形态、预设色板、复制与清除,并将值同步为 hex、rgb 或 hsl 三种格式之一。

基于 Nuxt UI 的 ColorPicker 组件封装

用法

默认按钮触发器展示当前色值,点击打开 popover 后从面板选择并同步 v-model:

<script setup lang="ts">
const value = ref("#0ea5e9")
</script>

<template>
  <MColorChooser v-model="value" />
</template>

formats 输出格式

在 popover 顶部切换 hexrgbhslcmyklab,当前值会转换为对应格式:

<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 插槽可完全接管触发器外观,同时通过 openvalue 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
idstring
namestring
format'hex'"hex" | "rgb" | "hsl" | "cmyk" | "lab"

当前激活的颜色格式。

formats["hex"]ColorFormat[]

启用的颜色格式 tab 列表,长度 >= 2 时在 popover 顶部渲染切换器。 仅一项时不渲染 tab,等价于 format

swatchesstring[] | string[][]

预设色板。 一维数组渲染为单行,二维数组渲染为多行分组。

trigger'button'"button" | "chip" | "input"

触发器形态。

  • button:色点 + 色值 / label 的常规按钮(默认)
  • chip:仅一个圆形色点
  • input:色点 leading + 可输入色值文本框
labelstring

trigger='button' 时按钮上的文本,未传则显示当前色值。

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

未选中颜色时占位的图标。

colorPickerPropsOmit<ColorPickerProps, "format" | "disabled" | "modelValue">

透传给 UColorPicker 的属性。 modelValueformatdisabled 由组件内部托管。

mode'click'M

The display mode of the popover.

content{ side: 'bottom', sideOffset: 8, collisionPadding: 8 }PopoverContentProps & Partial<EmitsToProps<PopoverContentImplEmits>>

The content of the popover.

arrowfalseboolean | PopoverArrowProps

Display an arrow alongside the popover. { rounded: true }

portaltruestring | false | true | HTMLElement

Render the popover in a portal.

referenceElement | VirtualElement

The reference (or anchor) element that is being referred to for positioning.

Accepts an element or a virtual element (anything with getBoundingClientRect), and can be changed reactively to re-anchor the popover (e.g. for a guided tour). If not provided will use the current component as anchor.

openDelaynumber

The duration from when the mouse enters the trigger until the hover card opens.

closeDelaynumber

The duration from when the mouse leaves the trigger or content until the hover card closes.

modelValuestring
closeOnSwatchtrueboolean

点击预设色后是否自动关闭弹层。

clearableboolean

是否在底部 actions 区显示清除按钮。

copyableboolean

actions 区显示复制按钮(基于 navigator.clipboard)。

disabledboolean

是否禁用。禁用时弹层不会打开、所有交互失效。

highlightboolean

Highlight the ring color like a focus state.

dismissibletrueboolean

When false, the popover will not close when clicking outside or pressing escape.

modalfalseboolean

The 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.

uiRecord<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

app.config.ts
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'
      }
    }
  }
})

Changelog

No recent changes
Copyright © 2025 - 2026 YiXuan - MIT License