Color Picker
A color field with a picker, a typed hex value, and swatches.
Preview
Loading...
import { ColorPicker } from "@/components/ui/ColorPicker";
export function ColorPickerDemo() {
return <ColorPicker defaultValue="#964CE1" />;
}Installation
Make sure that namespace is set in your component.json file. Namespace docs: Learn more about namespaces
pnpm dlx shadcn@latest add @aura/color-pickerManual
Copy and paste the class names utility into your utils/class-names.ts file.
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Copy and paste the color swatch component into your components/ui/ColorSwatch.tsx file.
"use client";
import * as React from "react";
import { cn } from "@/utils/class-names";
function ColorSwatch({
className,
color,
label,
selected,
...props
}: React.ComponentProps<"button"> & {
color: string;
label: string;
selected?: boolean;
}) {
return (
<button
type="button"
aria-label={label}
aria-pressed={selected}
data-slot="color-swatch"
className={cn(
"inline-flex size-3 items-center justify-center rounded-full border border-gray-7 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-8 aria-pressed:ring-2 aria-pressed:ring-accent-9",
className,
)}
style={{ backgroundColor: color }}
{...props}
/>
);
}
export { ColorSwatch };
Copy and paste the ColorPicker component into your components/ui/ColorPicker.tsx file.
"use client";
import * as React from "react";
import { cn } from "@/utils/class-names";
import { ColorSwatch } from "@/components/ui/ColorSwatch";
const presets = ["#964CE1", "#3D63DD", "#30A46C", "#E54D2E", "#F5D90A", "#111111"];
function ColorPicker({
className,
value,
defaultValue = "#964CE1",
onValueChange,
label = "Color",
}: {
className?: string;
value?: string;
defaultValue?: string;
onValueChange?: (value: string) => void;
label?: string;
}) {
const [uncontrolled, setUncontrolled] = React.useState(defaultValue);
const [text, setText] = React.useState(value ?? defaultValue);
const current = value ?? uncontrolled;
const id = React.useId();
const commit = (next: string) => {
if (value === undefined) setUncontrolled(next);
setText(next);
onValueChange?.(next);
};
return (
<div data-slot="color-picker" className={cn("flex w-fit flex-col gap-0.5", className)}>
<label htmlFor={id}>{label}</label>
<div className="flex items-center gap-0.5">
<input
type="color"
aria-label={`${label} picker`}
value={current}
className="size-4 shrink-0 cursor-pointer bg-transparent"
onChange={(event) => commit(event.target.value)}
/>
<input
id={id}
value={text}
spellCheck={false}
className="w-12 rounded-sm border border-gray-7 bg-gray-1 px-1 py-0.5 text-gray-12 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-8"
onChange={(event) => {
const next = event.target.value;
setText(next);
if (/^#[0-9a-fA-F]{6}$/.test(next)) commit(next);
}}
/>
</div>
<div className="flex items-center gap-0.5" role="group" aria-label="Preset colors">
{presets.map((preset) => (
<ColorSwatch
key={preset}
color={preset}
label={preset}
selected={current.toLowerCase() === preset.toLowerCase()}
onClick={() => commit(preset)}
/>
))}
</div>
</div>
);
}
export { ColorPicker };