Skip to content

Color Picker

A neo-brutalist style color picker component built on reka-ui Popover. Supports HEX/RGB/HSL color formats, an alpha channel, a preset color palette, and locally stored color history.

Demo

Preview

基础用法(HEX)

#EF476F

颜色格式

RGB
HSL

透明度通道(showAlpha)

#4A90D9

自定义预设颜色

尺寸

禁用状态

程序化控制(通过 ref 打开面板)

通过 pickerRef.open 可在外部按钮中打开或关闭颜色面板。

The color picker provides a saturation/brightness selection area, a hue slider, an opacity slider, a HEX input, preset colors, and history.

Installation

pnpm dlx brutx-vue@latest add color-picker

Usage

Basic Usage

vue
<script setup>
import { ref } from 'vue'
import { ColorPicker } from 'brutx-ui-vue'

const color = ref(null)
</script>

<template>
    <ColorPicker v-model="color" placeholder="Select color" />
</template>

Specifying Color Format

Supports hex (default), rgb, and hsl formats. modelValue outputs in the corresponding format:

vue
<script setup>
import { ref } from 'vue'
import { ColorPicker } from 'brutx-ui-vue'

const color = ref(null)
</script>

<template>
    <ColorPicker v-model="color" format="rgb" />
    <ColorPicker v-model="color" format="hsl" />
</template>

Alpha Channel

When showAlpha is enabled, the panel displays an opacity slider and the output value includes the alpha channel:

vue
<template>
    <ColorPicker v-model="color" :show-alpha="true" />
</template>

Preset Colors

Includes the Tailwind CSS default color palette out of the box, or you can customize presets:

vue
<script setup>
import { ref } from 'vue'
import { ColorPicker } from 'brutx-ui-vue'

const color = ref(null)
const presets = [
    '#FF6B6B',
    '#4ECDC4',
    '#FFE66D',
    '#EF476F',
    '#7FB069',
]
</script>

<template>
    <ColorPicker v-model="color" :presets="presets" :show-presets="true" />
</template>

Presets also support an object format with labels (optional disabled field to disable individual swatches):

vue
<script setup>
const presets = [
    { label: 'Coral Red', value: '#FF6B6B' },
    { label: 'Mint Green', value: '#4ECDC4' },
    { label: 'Deprecated', value: '#999999', disabled: true },
]
</script>

Color History

When showHistory is enabled, user-selected colors are automatically recorded to history, stored in localStorage by default:

vue
<template>
    <ColorPicker
        v-model="color"
        :show-history="true"
        :history-max="20"
        history-storage-key="my-app-color-history"
    />
</template>

Clearable

vue
<template>
    <ColorPicker v-model="color" :clearable="true" />
</template>

Disabled State

vue
<template>
    <ColorPicker v-model="color" disabled />
</template>

Sizes

SizeDescription
smSmall size
defaultDefault size
lgLarge size
vue
<template>
    <ColorPicker v-model="color" size="sm" />
    <ColorPicker v-model="color" size="default" />
    <ColorPicker v-model="color" size="lg" />
</template>

Data Types

FormatExampleDescription
hex#FF6B6B / #FF6B6B80Hexadecimal (two extra digits when alpha is included)
rgbrgb(255, 107, 107) / rgba(255, 107, 107, 0.5)RGB function notation
hslhsl(0, 100%, 71%) / hsla(0, 100%, 71%, 0.5)HSL function notation

Composables

The ColorPicker component's popup panel triggering, color format normalization, clearing, and confirmation logic has been extracted into a standalone useColorPicker composable. It can be used independently when you need to build a fully custom trigger or color palette. It manages panel open/close state, display value synchronization with modelValue, normalization to the target format, and triggers open / close / change / update:modelValue events through the provided emit.

ts
import { useColorPicker } from 'brutx-ui-vue'
import type { UseColorPickerOptions } from 'brutx-ui-vue'

const emit = defineEmits<{
    'update:modelValue': [value: string | null]
    'change': [value: string | null]
    'open': []
    'close': []
}>()

const {
    open,                  // Whether the panel is open
    displayValue,          // Current displayed value in the panel
    normalizedDisplay,     // Display string normalized to the target format
    swatchStyle,           // Inline style for the trigger swatch
    handlePanelUpdate,     // Panel value update callback
    handlePanelConfirm,    // Panel confirm callback
    handlePanelClear,      // Panel clear callback
    handleClearClick,      // Trigger clear button click callback
    handleTriggerKeydown,  // Trigger keyboard event callback
} = useColorPicker({
    modelValue,
    format: 'hex',
    showAlpha: false,
    disabled: false,
    emit,
})

Options

PropTypeDefaultDescription
modelValueMaybeRefOrGetter<string | null>nullCurrently selected color (supports v-model)
formatMaybeRefOrGetter<'hex' | 'rgb' | 'hsl'>'hex'Color format
showAlphaMaybeRefOrGetter<boolean>falseWhether to support the alpha channel
disabledMaybeRefOrGetter<boolean>falseWhether disabled
emitColorPickerEmitEvent emitter function (required, type matches the component's emits)

Return Values

PropertyTypeDescription
openRef<boolean>Whether the panel is open
displayValueRef<string | null>Current displayed value in the panel
normalizedDisplayComputedRef<string | null>Display string normalized by format (null if unparseable)
swatchStyleComputedRef<{ backgroundColor: string }>Inline style for the trigger swatch
handlePanelUpdate(value)(value: string | null) => voidCalled when panel value updates; syncs displayValue and triggers update:modelValue
handlePanelConfirm(value)(value: string | null) => voidCalled on panel confirm; triggers update:modelValue / change and closes the panel
handlePanelClear()() => voidCalled on panel clear; triggers update:modelValue(null) / change(null)
handleClearClick(event)(event: MouseEvent) => voidTrigger clear button click callback; stops event propagation and clears
handleTriggerKeydown(event)(event: KeyboardEvent) => voidTrigger keyboard event callback; Enter / Space opens the panel (no response when disabled)

Note: emit must be a function conforming to the ColorPickerEmit signature (i.e., the return value of the component's defineEmits). Color parsing and formatting are provided by parseColor / formatColor from @/lib/color.

Programmatic Control

ColorPicker exposes an open reactive ref via defineExpose, allowing the parent component to programmatically open or close the color panel. open is a Ref<boolean> that is two-way bound to the internal Popover, and can be read or written directly.

vue
<script setup>
import { ref } from 'vue'
import { ColorPicker } from 'brutx-ui-vue'

const pickerRef = ref()
const color = ref(null)
</script>

<template>
    <ColorPicker ref="pickerRef" v-model="color" />

    <button @click="pickerRef?.open = true">Open Panel</button>
    <button @click="pickerRef?.open = false">Close Panel</button>
</template>

Exposed API

Method/PropertyTypeDescription
openRef<boolean>Panel open/close state; readable and writable; set to true to open, false to close

Props

PropTypeDefaultDescription
modelValuestring | nullnullSelected color value, supports v-model
format'hex' | 'rgb' | 'hsl''hex'Color format
showAlphabooleanfalseWhether to support the alpha channel
presetsstring[] | ColorPreset[]Preset color list
showPresetsbooleantrueWhether to show preset colors
presetsLabelstringPreset area label text
showHistorybooleantrueWhether to show color history
historyMaxnumber8Maximum number of history entries
historyStorageKeystring'brutx-color-history'localStorage key for history
showInputbooleantrueWhether to show the input field
placeholderstringPlaceholder text
disabledbooleanfalseDisabled state
clearablebooleanfalseWhether clearable
size'sm' | 'default' | 'lg''default'Input size
namestringForm field name
idstringComponent ID
ariaLabelstringAccessibility label
openbooleanWhether the panel is open, supports v-model:open two-way binding
classstringCustom CSS class

Events

EventPayloadDescription
update:modelValuestring | nullTriggered when the color changes
changestring | nullTriggered when the panel closes and the value changes; also triggered by confirm/clear operations
openTriggered when the panel opens
closeTriggered when the panel closes
update:openbooleanTriggered when the panel open/close state changes; used with v-model:open

Accessibility

Trigger

KeyAction
Enter / SpaceOpen the panel (no response when disabled)
EscapeClose the panel

Saturation/Brightness Area

KeyAction
Left / RightAdjust saturation (step 1, Shift step 10)
Up / DownAdjust brightness (step 1, Shift step 10)

Hue Slider

KeyAction
Left / RightAdjust hue (step 1, Shift step 15)

Opacity Slider

KeyAction
Left / RightAdjust opacity (step 0.01, Shift step 0.1)

FAQ

Q: What happens to the previous modelValue format when switching format?

A: The component automatically normalizes the existing color value to the format corresponding to the current format. For example, when switching from hex to rgb, the previous #FF6B6B is automatically converted to rgb(255, 107, 107). No manual format conversion is needed.

Q: Where is color history stored? How do I clear it?

A: Color history is stored in the browser's localStorage by default, with the key controlled by the historyStorageKey prop (default: 'brutx-color-history'). It can be cleared via the browser developer tools' Application panel, or programmatically with localStorage.removeItem('brutx-color-history'). Setting a different historyStorageKey allows maintaining independent histories for different use cases.

Q: How does the output format change when showAlpha is enabled?

A: When the alpha channel is enabled, the output value includes alpha information. The hex format becomes 8 digits (e.g., #FF6B6B80), rgb becomes rgba(), and hsl becomes hsla(). When showAlpha is disabled, the output reverts to the standard format without opacity.

Brute force builds.