Glow Color
A colour swatch that is a duck field rather than an OS widget, with the eyedropper beside it where the browser has one.
InputsClient componentlucide-react
Preview
#C6F24E
Used for the accent and the glow.
fill
Shape
Outline
Installation
The CLI writes the source into your project and pulls in whatever it depends on.
$
pnpm dlx shadcn@latest add @duck/glow-colorPulls in @duck/theme, @duck/glow-input. Already installed items are skipped.
Usage
import { GlowColor, normalizeHex } from "@/components/ui/glow-color"The file lands in components/ui/glow-color.tsx and belongs to you from that point on. Edit it in place rather than wrapping it.
Props
Everything not listed here is forwarded to the underlying element.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | - | Controlled colour as #rrggbb. Shorthand and an alpha pair are accepted and normalised. |
| defaultValue | string | "#000000" | Uncontrolled starting colour. |
| onValueChange | (hex: string) => void | - | The colour, always as #rrggbb. Fires for the swatch and for an eyedropper pick — wire this one. |
| size | "sm" | "default" | "default" | 32px or 40px swatch. sm is the rail size. |
| eyedropper | boolean | true | Offer the screen picker where the browser has one. Chromium only, so the control appears after mount rather than on the server. |
| showValue | boolean | false | Print the hex beside the swatch in tabular mono. |
| frame | boolean | true | The sticker edge and the lime focus glow around the swatch. |
| swatchClassName | string | - | Styles the swatch. className styles the row it sits in. |
Rules
What keeps this component from turning into noise.
- A picked colour has no DOM event behind it, so it reports through onValueChange. onChange stays the swatch's own native event, for a form that reads the input directly.
- Values are normalised to #rrggbb before they reach the input, because input[type=color] accepts nothing else and renders anything else as black — which is how a #fff default becomes a black swatch with no error anywhere.
- There is no alpha channel. An eighth and ninth hex digit are dropped rather than half-honoured; if opacity matters, keep it in a separate control.
- The eyedropper is Chromium-only and the component says so by rendering it from a mounted effect. Do not gate it on a user agent string, and do not assume it is there.
- A rejected pick — Escape, a dismissed picker — is not an error and does not change the value.
