Forms
Color Picker
Accessible color picker wrapper built on react-aria-components, styled with the quebi design system. Includes an EyeDropper helper for sampling colors.
forminputcolorpicker
Swatch with hex field
A live color swatch paired with an editable hex input.
With eye dropper
Sample any pixel on screen using the browser EyeDropper API.
Swatch palette
Pick from a curated set of preset colors.
Source
Copy this into your project. Resolve its dependencies from the registryDependencies in the component's API entry.
"use client"
import { use } from "react"
import {
ColorPicker as ColorPickerPrimitive,
type ColorPickerProps as ColorPickerPrimitiveProps,
ColorPickerStateContext,
parseColor,
} from "react-aria-components"
import { Button } from "@/components/button"
import { cn } from "@/lib/utils"
/**
* ColorPicker — quebi design system
*
* A thin wrapper around react-aria-components' ColorPicker that lays out the
* trigger/swatch/inputs in a quebi-styled control row. Compose it with the
* react-aria color primitives (ColorSwatch, ColorArea, ColorSlider, etc.).
*
* The companion EyeDropper uses the browser EyeDropper API (where supported)
* to sample a color straight onto the picker's state.
*/
interface ColorPickerProps extends ColorPickerPrimitiveProps {
className?: string
}
const ColorPicker = ({ className, ...props }: ColorPickerProps) => {
return (
<div
data-slot="control"
className={cn("flex w-fit items-center gap-2", className)}
>
<ColorPickerPrimitive {...props} />
</div>
)
}
declare global {
interface Window {
EyeDropper?: new () => { open: () => Promise<{ sRGBHex: string }> }
}
}
const EyeDropperIcon = () => (
<svg
data-slot="icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="m2 22 1-1h3l9-9" />
<path d="M3 21v-3l9-9" />
<path d="m15 6 3.4-3.4a2.1 2.1 0 1 1 3 3L18 9l.4.4a2.1 2.1 0 1 1-3 3l-3.8-3.8a2.1 2.1 0 1 1 3-3l.4.4Z" />
</svg>
)
const EyeDropper = () => {
const state = use(ColorPickerStateContext)
if (!state) throw new Error("EyeDropper must be used within a ColorPicker")
if (typeof window !== "undefined" && !window.EyeDropper) {
return (
<span className="text-[12px] text-quebi-fg-muted">
EyeDropper is not supported in your browser.
</span>
)
}
return (
<Button
className="shrink-0"
aria-label="Eye dropper"
size="sq-md"
intent="outline"
onPress={() => {
const eyeDropper = window.EyeDropper ? new window.EyeDropper() : null
eyeDropper?.open().then((result) => state.setColor(parseColor(result.sRGBHex)))
}}
>
<EyeDropperIcon />
</Button>
)
}
export type { ColorPickerProps }
export { ColorPicker, EyeDropper }