A native color chooser paired with an editable hex field and a live swatch.
Workspace accent
Use a color that feels like your team.
import { ColorPicker } from "@/components/ballmac/color-picker"
export default function ColorPickerDemo() {
return (
<div className="w-full max-w-sm rounded-xl border bg-card p-5 shadow-sm">
<p className="mb-1 text-sm font-semibold">Workspace accent</p>
<p className="mb-4 text-xs text-muted-foreground">
Use a color that feels like your team.
</p>
<ColorPicker label="Workspace accent" defaultValue="#6d5ef7" />
</div>
)
}Installation
$ pnpm dlx shadcn@latest add @ballmac/color-pickerAdd the Ballmac items it builds on.
$ pnpm dlx shadcn@latest add @ballmac/i18nCopy the source into your project.
components/ballmac/color-picker.tsx// Ballmac UI: Color Picker. https://ui.ballmac.com/components/color-picker "use client" import * as React from "react" import { cn } from "@/lib/utils" import { useMessages } from "@/lib/ballmac/i18n" type ColorPickerProps = Omit< React.ComponentProps<"div">, "onChange" | "defaultValue" > & { /** Controlled six-digit hexadecimal color. */ value?: string /** Initial color when uncontrolled. */ defaultValue?: string /** Called when either control edits the color. */ onValueChange?: (value: string) => void /** Accessible name of the picker. */ label?: string /** Native form field name. */ name?: string /** Disable editing. */ disabled?: boolean } function ColorPicker({ value, defaultValue = "", onValueChange, label, name, disabled = false, className, ...props }: ColorPickerProps) { const msg = useMessages() label ??= msg("color-picker.label", "Color") const [internal, setInternal] = React.useState(defaultValue) const current = value ?? internal const valid = /^#[0-9a-fA-F]{6}$/.test(current) function commit(next: string) { if (value === undefined) setInternal(next) onValueChange?.(next) } return ( <div data-slot="color-picker" className={cn( "flex h-10 w-full min-w-0 items-center gap-2 rounded-md border border-input bg-background px-2 shadow-xs transition-[border-color,box-shadow] duration-150 motion-reduce:transition-none focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50", className, )} {...props} > <input data-slot="color-picker-native" type="color" aria-label={msg("color-picker.choose", "Choose {label}", { label: label.toLowerCase() })} disabled={disabled} value={current} onChange={(event) => commit(event.currentTarget.value)} className="size-7 shrink-0 cursor-pointer rounded border border-border bg-transparent p-0.5 disabled:opacity-50" /> <input data-slot="color-picker-text" type="text" aria-label={msg("color-picker.hexValue", "{label} hex value", { label })} aria-invalid={current && !valid ? true : undefined} name={name} disabled={disabled} value={current} onChange={(event) => commit(event.currentTarget.value)} placeholder={msg("color-picker.hexColor", "Hex color")} maxLength={7} spellCheck={false} className="min-w-0 flex-1 bg-transparent font-mono text-sm text-foreground outline-none placeholder:font-sans placeholder:text-muted-foreground disabled:opacity-50" /> <span aria-hidden="true" className="size-6 shrink-0 rounded-md border border-border" style={{ backgroundColor: valid ? current : "var(--muted)" }} /> </div> ) } export { ColorPicker, type ColorPickerProps }Update the import paths to match your project setup.
Usage
import { ColorPicker } from "@/components/ballmac/color-picker"The full example is in the Code tab above.
Examples
States and variants
Annotation color
import { ColorPicker } from "@/components/ballmac/color-picker"
export default function ColorPickerStates() {
return (
<div className="w-full max-w-sm">
<p className="mb-2 text-sm font-medium">Annotation color</p>
<ColorPicker label="Annotation color" defaultValue="#2f9e78" />
</div>
)
}API reference
| Prop | Type | Default |
|---|---|---|
valueControlled six-digit hexadecimal color. | string | — |
defaultValueInitial color when uncontrolled. | string | "" |
onValueChangeCalled when either control edits the color. | (value: string) => void | — |
labelAccessible name of the picker. | string | — |
nameNative form field name. | string | — |
disabledDisable editing. | boolean | false |
Also accepts the standard attributes of its root element.
Accessibility
| Key | Action |
|---|---|
| Tab | Moves between color and text inputs |
| Enter | Accepts a native color selection |
Use with AI
A native color chooser paired with an editable hex field and a live swatch. With the shadcn MCP server set up (guide), ask your agent:
Add the Ballmac UI Color Picker (@ballmac/color-picker) to this project with the shadcn MCP, then use it where it fits.
Use it for
- Choose a custom brand or annotation color
- Edit a color precisely by hexadecimal value
Not for
- Use theme tokens for application chrome
Registry JSON: https://ui.ballmac.com/r/color-picker.json
Credits
Free to use in personal and commercial projects.
- npm
- None
- Registry
- @ballmac/i18nshadcn/utils
Pairs well with
Input
A text input in three heights that match Button, plus InputGroup and InputGroupAddon for leading or trailing icons, units and domains.
Calendar
A date grid for one day, several days or a range, with month and year selects, week numbers, disabled rules and range-end styling, on React DayPicker.
Combobox
A searchable single-choice select with groups, descriptions, keywords, clearable value, invalid state and hidden-input form submission.
Currency Input
A locale-aware money field that formats on blur while keeping editing and caret behavior simple.