Framework Integration
ew-color-picker depends only on plain DOM and events — no framework runtime — so the same approach works everywhere: create the instance on mount, call destroy() on unmount, and sync controlled values through setColor().
Below are minimal, copy-paste wrappers for four frameworks. No official framework packages are published; the reasoning is covered in Comparison & Positioning.
Common rules
- One instance per mount point:
elaccepts either a selector string or a DOM element; prefer the element reference so multiple pickers never collide on selectors. - Always call
destroy()on unmount: the instance registers adocumentclick listener. Leaking it breaks other instances by toggling their panels. - Guard controlled sync against loops: call
setColor()when the external value changes, butsetColor()fireschangeagain — compare the incoming value first. - Import both stylesheets:
index.cssandinput-number.css(the number input styles ship in a separate file). - SSR safety: create the instance only in browser-side lifecycle hooks (
useEffect/onMounted/ngAfterViewInit/onMount).
import ewColorPicker from '@ew-color-picker/ew-color-picker'
import '@ew-color-picker/style/dist/index.css'
import '@ew-color-picker/style/dist/input-number.css'React
import { useEffect, useRef } from 'react'
import ewColorPicker from '@ew-color-picker/ew-color-picker'
import '@ew-color-picker/style/dist/index.css'
import '@ew-color-picker/style/dist/input-number.css'
interface Props {
value: string
onChange: (color: string) => void
}
export function ColorField({ value, onChange }: Props) {
const hostRef = useRef<HTMLDivElement>(null)
const pickerRef = useRef<ewColorPicker | null>(null)
useEffect(() => {
const picker = new ewColorPicker({
el: hostRef.current!,
defaultColor: value,
})
picker.on('change', (color: string) => onChange(color))
pickerRef.current = picker
return () => {
picker.destroy()
pickerRef.current = null
}
}, [])
useEffect(() => {
pickerRef.current?.setColor(value)
}, [value])
return <div ref={hostRef} />
}React 19 StrictMode mounts effects twice; the return () => picker.destroy() cleanup above prevents leftover instances.
Vue 3
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import ewColorPicker from '@ew-color-picker/ew-color-picker'
import '@ew-color-picker/style/dist/index.css'
import '@ew-color-picker/style/dist/input-number.css'
const props = defineProps<{ modelValue: string }>()
const emit = defineEmits<{ 'update:modelValue': [string] }>()
const hostRef = ref<HTMLDivElement>()
let picker: ewColorPicker | null = null
onMounted(() => {
picker = new ewColorPicker({
el: hostRef.value!,
defaultColor: props.modelValue,
changeColor: (color: string) => emit('update:modelValue', color),
})
})
watch(
() => props.modelValue,
(value) => {
if (picker && picker.getColor() !== value) picker.setColor(value)
},
)
onBeforeUnmount(() => {
picker?.destroy()
picker = null
})
</script>
<template>
<div ref="hostRef" />
</template>Usage is the standard v-model:
<ColorField v-model="color" />Angular
import {
AfterViewInit,
Component,
ElementRef,
EventEmitter,
Input,
OnDestroy,
Output,
ViewChild,
} from '@angular/core'
import ewColorPicker from '@ew-color-picker/ew-color-picker'
@Component({
selector: 'ew-color-field',
standalone: true,
template: '<div #host></div>',
})
export class ColorFieldComponent implements AfterViewInit, OnDestroy {
@ViewChild('host', { static: true }) host!: ElementRef<HTMLDivElement>
@Input() value = '#ffffff'
@Output() valueChange = new EventEmitter<string>()
private picker?: ewColorPicker
ngAfterViewInit(): void {
this.picker = new ewColorPicker({
el: this.host.nativeElement,
defaultColor: this.value,
changeColor: (color: string) => this.valueChange.emit(color),
})
}
ngOnDestroy(): void {
this.picker?.destroy()
}
}Use it with two-way binding:
<ew-color-field [(value)]="color" />Solid
import { onCleanup, onMount } from 'solid-js'
import ewColorPicker from '@ew-color-picker/ew-color-picker'
import '@ew-color-picker/style/dist/index.css'
import '@ew-color-picker/style/dist/input-number.css'
export function ColorField(props: { value: string; onChange: (color: string) => void }) {
let host!: HTMLDivElement
let picker: ewColorPicker | undefined
onMount(() => {
picker = new ewColorPicker({ el: host, defaultColor: props.value })
picker.on('change', (color: string) => props.onChange(color))
})
onCleanup(() => picker?.destroy())
return <div ref={host} />
}Solid's fine-grained reactivity needs no extra plumbing: call setColor() inside a createEffect that reads props.value.
FAQ
Can I pass a selector string? Yes, el: '#picker' works. Inside a framework, prefer the element reference so duplicate ids cannot clash.
Why did another picker close my panel? An instance was not destroyed on unmount, so its leftover document click listener toggles panels everywhere.
Does the change event loop forever? Only when you write the value back to the component and the component writes it back with setColor(). Compare old and new values to break the loop.
Do I need official wrapper packages? The code above is the complete wrapper. If a project uses it in several places, extract these twenty lines into your own component rather than depending on a third-party package.