Color Picker

An interactive color picker component with RGB, HSV, and hex support. Features include color panel selection, hue slider, hex input, clipboard integration, and eyedropper tool.

Raws

Installation

npm install react-colorful
color-picker.tsx
1
"use client";
2
3
import { Button } from "@/components/website/ui/button";
4
import { Input } from "@/components/website/ui/input";
5
import { Label } from "@/components/website/ui/label";
6
import {
7
Popover,
8
PopoverContent,
9
PopoverTrigger,
10
} from "@/components/website/ui/popover";
11
import { cn } from "@/lib/utils";
12
import { Copy, Pipette } from "lucide-react";
13
import { HexColorPicker } from "react-colorful";
14
import { toast } from "sonner";
15
16
interface ColorPickerProps {
17
color: string
18
onChange: (color: string) => void
19
label: string
20
isEyeDroppper?:boolean
21
className?:string
22
}
23
24
export function ColorPicker({
25
color,
26
onChange,
27
label,
28
isEyeDroppper = false,
29
className,
30
}: ColorPickerProps) {
31
function copyToClipboard() {
32
navigator.clipboard.writeText(color);
33
toast("Copied!", {
34
description: `${color} copied to clipboard`,
35
duration: 2000,
36
});
37
}
38
39
async function useEyeDropper() {
40
if (!("EyeDropper" in window)) {
41
toast.error("Not supported", {
42
description: "Eyedropper is not supported in your browser",
43
duration: 3000,
44
});
45
return;
46
}
47
48
try {
49
// @ts-expect-error - EyeDropper is not in the TypeScript DOM types yet
50
const eyeDropper = new window.EyeDropper();
51
const result = await eyeDropper.open();
52
onChange(result.sRGBHex);
53
} catch (e) {
54
console.error("Error using eyedropper", e);
55
}
56
}
57
58
return (
59
<div className={cn("flex items-center gap-2",className)}>
60
<Label className="w-24">{label}</Label>
61
<Popover>
62
<PopoverTrigger asChild>
63
<Button
64
variant="outline"
65
className="h-8 w-12 border-2 p-0"
66
style={{ backgroundColor: color }}
67
>
68
<span className="sr-only">Pick a color</span>
69
</Button>
70
</PopoverTrigger>
71
<PopoverContent className="w-full p-3 bg-primary-foreground">
72
<HexColorPicker
73
color={color}
74
onChange={onChange}
75
className="!w-full"
76
/>
77
<div className="mt-2 flex w-full gap-2">
78
<Input
79
value={color}
80
onChange={(e) => onChange(e.target.value)}
81
className="h-10 w-full"
82
/>
83
<Button
84
variant="outline"
85
size="icon"
86
onClick={copyToClipboard}
87
className="h-10 w-12 shrink border-gray-300 bg-gray-100 text-gray-900 hover:bg-gray-200"
88
style={{ borderRadius: "6px" }}
89
>
90
<Copy className="h-4 w-4" />
91
<span className="sr-only">Copy color</span>
92
</Button>
93
</div>
94
95
{isEyeDroppper && (
96
<div className="mt-2 flex gap-2">
97
<Button
98
variant="outline"
99
size="icon"
100
onClick={useEyeDropper}
101
className="h-10 w-10 border-gray-300 bg-gray-100 text-gray-900 hover:bg-gray-200"
102
style={{ borderRadius: "6px" }}
103
>
104
<Pipette className="h-4 w-4" />
105
<span className="sr-only">Pick color</span>
106
</Button>
107
108
<div
109
className="h-10 flex-1"
110
style={{ backgroundColor: color, borderRadius: "6px" }}
111
/>
112
</div>
113
)}
114
</PopoverContent>
115
</Popover>
116
</div>
117
);
118
}

Props

PropsTypeDefaultDescription
colorstringThe current color value.
onChange(color: string) => voidCallback fired when the color is changed.
labelstringLabel displayed above the color picker.
isEyeDroppperbooleanfalseWhether to enable the eyedropper feature.
classNamestringfalseWhether to enable the eyedropper feature.