Skip to content

vColorPickerVue 3 Color Picker

A lightweight, accessible color picker component for Vue 3

Demo

Selected color: #ff0000

Localization

English locale: #3b82f6

Japanese locale: #10b981

vue
<template>
  <colorPicker
    v-model="color"
    locale="en-US"
    :messages="{ moreColors: 'Custom Label...' }"
  />
</template>

Placement

The panel auto-detects available viewport space by default. You can lock it to any side with the placement prop.

Pinned to top-end: #f59e0b

vue
<colorPicker v-model="color" placement="top-end" />
<colorPicker v-model="color" placement="bottom" /> <!-- vertical locked, horizontal auto -->

Installation

bash
npm install vcolorpicker -S

Usage

Register the plugin in main.js:

js
import { createApp } from 'vue'
import vcolorpicker from 'vcolorpicker'
import App from './App.vue'

const app = createApp(App)
app.use(vcolorpicker)
app.mount('#app')

Use in your component:

vue
<template>
  <colorPicker v-model="color" />
</template>

<script setup>
import { ref } from 'vue'
const color = ref('#ff0000')
</script>

Props

PropTypeDefaultDescription
v-model / modelValuestringCurrent color value
defaultColorstring#000000Color the "Default" button resets to
disabledbooleanfalseDisabled state
locale'zh-CN' | 'en-US' | 'ja-JP'AutoBuilt-in panel labels; follows <html lang> / navigator.language when omitted
messagesPartial<ColorPickerMessages>Override built-in labels with custom text
placementColorPickerPlacement'auto'Panel placement: 'auto', 'top', 'bottom', 'top-start', 'top-end', 'bottom-start', 'bottom-end'. 'auto' picks based on available viewport space; directional values lock that axis

Events

EventPayloadDescription
change(color: string)Color value changed
update:modelValue(color: string)v-model sync event
openPanel opened
closePanel closed (outside click, Esc, or after selection)
hover(color: string)Swatch hover; emits empty string on leave
vue
<colorPicker v-model="color" @change="onColorChange" />

Imperative API

Methods exposed via template ref:

vue
<script setup lang="ts">
import { ref } from 'vue'
import type { ColorPickerInstance } from 'vcolorpicker'

const pickerRef = ref<ColorPickerInstance>()
const color = ref('#ff0000')

const openProgrammatically = () => pickerRef.value?.open()
</script>

<template>
  <colorPicker ref="pickerRef" v-model="color" />
  <button @click="openProgrammatically">Open Panel</button>
</template>
MethodDescription
open()Open the panel (no-op when disabled)
close()Close the panel
focus()Move focus back to the trigger button

Accessibility

  • Trigger button and every swatch are reachable via Tab
  • Enter / Space activates; / on a focused trigger also opens the panel
  • Esc closes the panel and returns focus to the trigger
  • Trigger carries role="button", aria-haspopup="dialog", aria-expanded; the panel uses role="dialog"; every swatch has aria-label="#RRGGBB"
  • Focus rings use :focus-visible, so mouse users are not distracted

SSR / Nuxt

  • When document / navigator are unavailable (Node SSR), the initial locale falls back to zh-CN (or the explicit locale prop) so server and client render identically — no hydration mismatch
  • Real language detection runs after onMounted. To avoid a post-mount flicker from Chinese to another language, pass an explicit locale prop in SSR projects
  • The MutationObserver watching <html lang> is a module-level singleton — multiple component instances share a single observer

CSS Variables

Override these custom properties to theme the component without piercing selectors:

css
.m-colorPicker {
  --vcp-swatch-size: 15px;
  --vcp-panel-width: 190px;
  --vcp-panel-bg: #fff;
  --vcp-panel-border: 1px solid #ddd;
  --vcp-panel-radius: 2px;
  --vcp-panel-shadow: 0 8px 24px rgba(0, 0, 0, .18);
  --vcp-panel-padding: 10px;
  --vcp-text-color: #333;
  --vcp-focus-color: #4e81bb;
  --vcp-transition: .3s ease;
  --vcp-z-index: 10000;
}

Example — dark theme:

css
.dark .m-colorPicker {
  --vcp-panel-bg: #1f1f1f;
  --vcp-panel-border: 1px solid #333;
  --vcp-text-color: #eee;
}

TypeScript

Types exported from the package:

ts
import type {
  ColorPickerProps,
  ColorPickerEmits,
  ColorPickerExposed,
  ColorPickerInstance,
  ColorPickerLocale,
  ColorPickerMessages,
  ColorPickerPlacement
} from 'vcolorpicker'

FAQ

Does vColorPicker support Vue 3?

Yes. vColorPicker is built for Vue 3 and can be used with a standard v-model API.

Can I switch the panel language?

Yes. Set locale="zh-CN", locale="en-US" or locale="ja-JP" to use built-in translations, or pass messages to override any label.

Does it work with TypeScript?

Yes. The package ships with full type declarations — props, emits, instance methods, and helper types.

Does it support the native browser color picker?

Yes. Clicking More Colors... opens the native HTML5 color input in supported browsers.

Is it accessible to keyboard and screen reader users?

Yes. Tab to focus, Enter / Space to activate, Esc to close, and ARIA roles / labels are all wired up.

Sponsors