shadcn.io is not affiliated with official shadcn/ui
Color Picker Dialog Block for React
A brand-kit page with its colour dialog shown open: an inline saturation and hue picker with opacity, HEX, RGB and HSL fields, eight named presets, five recent colours, a Copy button and a contrast readout against white and dark text.
Installation
Overview
Let people choose a brand colour and know whether text will read on it, with this colour dialog for React with Base UI. It opens from the Brand kit page of Hueloft, a brand-kit tool: the header holds an outline Button with a swatch of the current colour, and the page, a large mark, a button and a row of swatches, is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The dialog draws the catalog Color Picker inline, a saturation and lightness area with hue and opacity sliders, and an eyedropper only where the browser has one. Tabs hold HEX, RGB and HSL fields that type back into the same colour, a Copy Button copies the open format, eight named presets and a Recent row of five set it in one press, and a readout works out the contrast ratio on white and on dark. Use colour, the only Shine Button, recolours the mark and the button behind it. For preview the dialog is drawn open in place when the page loads; the header button opens the real Dialog, with the same state. For brand kits, theme editors, design tools and any app that lets people pick a colour.
FAQ
Why is the dialog already open, and what do I keep?
So you can see it without a click. On load the dialog is a copy drawn in place over the page: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The header's Brand colour button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same ColourFields component and share the block's state, so what you set in the copy is there in the real one. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.
Why does this block use raw colours when the others use tokens only?
Because the colours are the visitor's own content: a brand colour is what the dialog is for. The swatches, the header button's dot and the drawn mark carry the chosen colour inline through a CSS variable, each marked with a code comment, and the digits are kept without the hash so no colour literal sits in the source. Everything else, the dialog, the tabs, the buttons and the focus rings, is theme tokens in light and dark.
How is the contrast worked out?
By the WCAG 2.2 formula, in a pure function: each channel is linearised, the relative luminance is 0.2126 red plus 0.7152 green plus 0.0722 blue, and the ratio is the lighter luminance plus 0.05 over the darker plus 0.05. The colour is compared with white and with a near-black ink, and the better pairing gets the verdict: 7 to 1 is AAA, 4.5 AA, 3 AA for large text, anything lower below AA. It ignores opacity, and it says only what the maths gives, not whether your brand looks right.
What stays local, and how do I wire it for real?
Everything. Use colour recolours the drawn page in local state, moves the colour to the front of Recent and says so in a polite status message; nothing is saved. The clipboard is the one thing the page touches. In your app save the colour in use in the format your design tokens take, and keep Recent per user. The HEX, RGB and HSL fields check what you type when you leave the field or press Enter, and say what is wrong instead of changing the colour.
Is it accessible from the keyboard?
Yes. The real dialog is named by its title and described by its sentence, focus is trapped while it is open, and Escape, Cancel and the close button return focus to the header button. The trigger is passed to DialogTrigger through render, and the dialog is controlled with open and onOpenChange. The copy shown on load moves no focus; Escape inside it and its close button close it and put focus back on the header button. The colour area and the sliders move with the arrow keys, the presets are a radio group, and each recent colour is a button named by its hex value.
How does it look on a phone?
The picker and the tabs stack into one column. The copy shown on load docks to the foot of the page as a bottom sheet with Use colour pinned at the bottom, and everything above it scrolls. The real dialog keeps the Dialog's own phone layout: a sheet stuck to the bottom of the screen.
Related
- Pro
Brand Colour Picker Form
Numbers and pickersA brand colour field that makes a scale: a hex input and the colour picker kept in sync, eight named presets, and five derived steps by lightness, each with its hex and a copy button.
- Pro
A writing app's document page with its type style dialog shown open: a family from three system stacks, weight, size from 12 to 48 pixels, line height and letter spacing, a live specimen and the CSS it makes with a Copy button.
- Pro
Appearance Settings
Appearance and localeAn appearance settings panel that previews instead of applying: a drawn app window that wears the choices, theme and contrast cards with a drawn thumbnail each, a text-size slider with a sample sentence and a reduce motion switch with a replay.
- Pro
Tag Manager Dialog
Pickers and searchAn expense tracker's tag dialog shown open: a search, a create row with five swatches, a list of eight tags you rename in place, merge or delete after a confirm, an always-there Undo, and the drawn transactions following.
- Pro
A time tracker's Today page with a preferences sheet shown open where each setting shows its effect: a theme choice over a preview card, a text size and a reduce-motion switch acting on a sample, a default view and two behaviour switches.
- Pro
Select Template Dialog
Pickers and searchA documents app's new-document dialog shown open: six icon tiles in two columns that move with the arrow keys and jump on a typed letter, Popular and New badges, a Create button that names the choice, and the new file landing on the home.