DEV Community

Sohail Khan
Sohail Khan

Posted on

ChromaPanel: A Modern React Color Picker with Eyedropper, Image Sampling, Gradients, and More

A color picker looks like a simple UI component until you need to use one in a real product.

At first, you may only need a HEX color field.

Then the requirements start growing.

Users want a color wheel. Designers want exact RGB and HSL values. Your settings page needs predefined brand colors. Someone asks to pick a color from an uploaded image. Another user wants an eyedropper. Your form needs validation. Keyboard navigation has to work. And eventually you may need gradients, OKLCH, Display P3, or accessible contrast checks.

At that point, a basic React color picker is no longer enough.

That is the problem I wanted to solve with ChromaPanel.

ChromaPanel is an open-source React color picker built for forms, settings pages, toolbars, theme editors, design tools, and other interfaces where users need more than a simple HEX picker.

It gives you multiple ways to choose a color while keeping them behind one React API.

What is ChromaPanel?

ChromaPanel is a React color picker component that can be used as a small color input or as a complete inline color panel.

It includes:

You can use everything together or only import the parts your application needs.

Install the React color picker

Getting started is intentionally simple.

npm install chroma-panel

Enter fullscreen mode Exit fullscreen mode

There is no provider that you need to add around your application.

There is also no separate CSS file you need to import for the standard setup.

Once the package is installed, you can render a working React color picker with ColorInput.

import { ColorInput } from "chroma-panel";

export function BrandColor() {
  return <ColorInput defaultValue="#3366cc" />;
}

Enter fullscreen mode Exit fullscreen mode

ColorInput displays a color swatch and opens ChromaPanel in a popover when the user clicks it.

For many forms and settings pages, that may be all you need.

Using ChromaPanel as a controlled React color picker

Most real applications need to keep the selected color in React state.

ChromaPanel supports the normal controlled component pattern.

import { useState } from "react";
import { ColorInput } from "chroma-panel";

export function AccentColorPicker() {
  const [color, setColor] = useState("#3366cc");

  return (
    <ColorInput
      value={color}
      onChange={(result) => setColor(result.hex)}
      aria-label="Accent color"
    />
  );
}

Enter fullscreen mode Exit fullscreen mode

The useful part here is that onChange does not only give you a HEX string.

The result contains different representations of the selected color, so your application can use the format it actually needs.

You can update a live preview with onChange while the user is dragging and use onChangeComplete when the interaction finishes.

<ColorInput
  value={color}
  onChange={(result) => setColor(result.hex)}
  onChangeComplete={(result) => saveColor(result.hex)}
/>

Enter fullscreen mode Exit fullscreen mode

This is useful when saving the value makes a network request, creates an undo entry, updates a database, or runs another expensive operation.

The UI can remain responsive without sending a request for every tiny movement of the color picker.

Need an inline color picker instead?

Sometimes a popover is not the right UI.

A design editor, theme builder, drawing tool, or customization page may need the entire React color picker to stay visible.

That is what ChromaPanel is for.

import { ChromaPanel } from "chroma-panel";

export function ThemeEditor() {
  return (
    <ChromaPanel
      defaultValue="#3366cc"
      modes={["wheel", "sliders", "palettes"]}
    />
  );
}

Enter fullscreen mode Exit fullscreen mode

The modes property is important.

You do not have to show every feature just because the package supports it.

A branding form may only need palettes.

A design tool may need sliders, a wheel, and image sampling.

A simple theme editor may only need the wheel.

This makes it possible to use the same color picker package across different parts of an application without giving every user the same large interface.

Color wheel

The wheel gives users a visual way to explore colors.

Instead of typing values, they can move around the hue wheel and adjust the color visually.

This works well when choosing colors is part of a creative interface such as a theme editor, website builder, drawing tool, product customizer, or design system.

It is also useful when users know roughly what color they want but do not know its HEX or RGB value.

RGB, HSL and HSB sliders

Sometimes visual selection is not precise enough.

Developers and designers often need exact channel values.

ChromaPanel includes per-channel controls for RGB, HSL, HSB/HSV, and alpha.

That means someone can visually find a color first and then fine-tune the exact numbers without switching to another tool.

The same React color picker can therefore work for casual users and people who need precise color control.

Searchable color palettes

Many applications should not allow completely arbitrary colors.

A company may have an approved brand palette. A theme builder may provide a set of design tokens. A product customizer may only support colors that can actually be manufactured.

ChromaPanel supports named palettes and searchable swatches, so you can provide those approved colors directly inside the picker.

Instead of building a separate palette component beside your color picker, both experiences can live inside the same UI.

The 120-color pencils mode

Pencils mode provides a large grid of ready-made colors.

Despite the name, it is not a drawing tool. It is a quick color-selection interface inspired by physical sets of colored pencils.

There are 120 colors available by default, and the set can be replaced when your product needs something different.

This mode is useful when users want to explore many predefined colors quickly without working with sliders or numerical values.

Pick colors from an image

This is one of the areas where a simple React color picker can quickly become a much bigger feature.

Imagine a user uploads a company logo and wants to create a matching theme.

Or they upload a product photo and want to use one of its main colors.

With ChromaPanel's image mode, a user can drop, paste, or select an image.

The React color picker can extract dominant colors from that image and display them as swatches.

The user can also select an exact pixel from the image.

You can use the image extraction API without showing the full color picker as well.

import { extractPalette } from "chroma-panel";

const { swatches } = await extractPalette(file, {
  maxColors: 8,
});

Enter fullscreen mode Exit fullscreen mode

This makes the same functionality useful for automatic theme generation, logo analysis, image editors, design applications, avatar customization, and other tools.

Image processing is bounded and downscaled rather than processing an unlimited full-size image directly.

There is also a separate worker entry point for applications that want to move heavier image processing away from the main thread.

A React color picker with an eyedropper

ChromaPanel also includes support for the browser EyeDropper API.

Where that browser API is available, users can pick a color from somewhere else on their screen.

This can be especially useful inside design tools, theme builders, website editors, and other visual applications.

The important part is that unsupported browsers do not need special handling from your UI just to hide the normal picker control.

There is also a useEyedropper hook if you want to create your own eyedropper button somewhere else in your interface.

It behaves like a real form control

A surprisingly important part of a React color picker is how it works inside forms.

You should not have to create hidden inputs, manually synchronize values, and rebuild standard browser behavior just because the input happens to select a color.

ColorInput can take a name and submit its value with FormData.

<form action={saveProfile}>
  <label htmlFor="profile-color">Profile color</label>

  <ColorInput
    id="profile-color"
    name="profileColor"
    defaultValue="#3366cc"
    format="hex"
    required
  />

  <button type="submit">Save</button>
</form>

Enter fullscreen mode Exit fullscreen mode

It also supports normal behaviors such as required, disabled, and form.reset().

That makes ChromaPanel particularly useful for settings screens, account customization, admin panels, SaaS dashboards, onboarding forms, and theme settings.

Accessibility is part of the component

Color pickers can be difficult to make accessible.

Many visual pickers are built almost entirely around pointer interactions. That works with a mouse, but it can become frustrating or impossible with a keyboard or screen reader.

ChromaPanel uses real range inputs for its color axes.

That allows standard browser keyboard behavior to do much of the work.

Arrow keys can change values. Page Up and Page Down make larger movements. Home and End move to the limits.

Values are announced with meaningful text rather than exposing only an unexplained number.

The popover manages focus, closes with Escape, and returns focus to its trigger.

Swatches use buttons with accessible names, and the component also respects reduced-motion and forced-color preferences.

Accessibility should not be something that gets added after a React color picker is already built. It affects the way the component itself should work.

Modern CSS colors: OKLCH, OKLab and Display P3

HEX and RGB are still everywhere, but modern CSS supports much more.

ChromaPanel includes color utilities for working with:

OKLCH, OKLab, Lab, LCH, sRGB, and Display P3.

For example:

import {
  parseColor,
  isInGamut,
  mapToGamut,
  serializeColor,
} from "chroma-panel/color";

const brand = parseColor("oklch(72% 0.18 250)");

if (brand && !isInGamut(brand, "srgb")) {
  const fallback = mapToGamut(brand, "srgb");

  console.log(serializeColor(fallback));
}

Enter fullscreen mode Exit fullscreen mode

These utilities do not require React or the DOM.

They can therefore also be used as general TypeScript color utilities inside your application.

This becomes useful when building design systems that are moving toward OKLCH, wide-gamut colors, and modern CSS color workflows.

A gradient color picker for React

Solid colors are not always enough either.

ChromaPanel provides a separate GradientEditor entry point for building linear and radial gradients.

import {
  GradientEditor,
  gradientToCss,
} from "chroma-panel/gradient";

Enter fullscreen mode Exit fullscreen mode

Gradient stops can be changed with the keyboard, and the utilities can turn the gradient model back into CSS.

The gradient tools are kept in a separate entry point.

That means an application that only needs a solid React color picker does not need to include the gradient editor code.

This separation matters because feature-rich UI libraries should not force every feature into every bundle.

Zero runtime dependencies

ChromaPanel has no runtime dependencies.

React and React DOM are peer dependencies, meaning the package uses the React installation that already exists in your application.

TypeScript declarations are included as well, so there is no separate @types package to install.

It supports React 16.14 and newer, including React 19.

It also provides ESM and CommonJS builds.

What about bundle size?

This is an important trade-off.

ChromaPanel is not trying to be the smallest React color picker on npm.

The complete package gives you much more functionality than a basic saturation box and hue slider.

With all five modes, the measured addition to a Vite production build is about 23.1 kB gzipped.

Using the panel shell with one mode is around 15 kB gzipped.

If your application only needs a tiny HEX picker, a smaller library such as react-colorful can make more sense.

But if your application would otherwise need a color picker, separate palettes, an eyedropper implementation, an image color picker, gradient editing, color conversions, accessibility work, and form integration, comparing only the size of the basic picker does not tell the full story.

Import only the modes you need

If you do not need all five modes, you can use the smaller entry points.

import { ChromaPanel } from "chroma-panel/panel";
import { wheelMode } from "chroma-panel/modes";

export function SimplePicker() {
  return <ChromaPanel modes={[wheelMode]} />;
}

Enter fullscreen mode Exit fullscreen mode

This is useful when you want ChromaPanel's API and behavior without including every available color-selection mode.

Works with modern React stacks

ChromaPanel is not tied to one UI framework.

The documentation includes guidance for Next.js, Vite, Remix, shadcn/ui, Material UI, React Aria, React Hook Form, Tailwind CSS, and server-rendered applications.

For example, if your project already uses shadcn/ui, you can let shadcn's Popover, Dialog, or Sheet own the surrounding interface and render ChromaPanel inside it.

ChromaPanel does not require shadcn/ui, Radix UI, or Base UI as dependencies.

That is useful when you want a React color picker that fits your existing design system rather than forcing another UI framework into the application.

When ChromaPanel makes sense

I built ChromaPanel for applications where color selection is part of the product rather than just a small decorative field.

If you are building a theme editor, design system, SaaS settings page, website builder, graphics tool, product customizer, brand editor, admin dashboard, CMS, or another interface with serious color controls, having these capabilities behind one API can remove a lot of custom work.

But there is an equally important point.

If your entire requirement is simply:

“Let the user choose a HEX color.”

then you probably do not need every feature ChromaPanel provides.

A smaller React color picker can be the right choice.

Choosing a library should be based on what your interface actually needs, not the number of features printed on its README.

Why I built it

The main idea behind ChromaPanel was not to build another variation of the same basic React color picker.

It was to create a color-selection component that could grow with a real application.

You can start with:

<ColorInput defaultValue="#3366cc" />

Enter fullscreen mode Exit fullscreen mode

and stop there.

Or the same project can later add palettes, image sampling, precise sliders, gradients, modern CSS color spaces, accessibility helpers, contrast tools, and custom modes without replacing the original color picker.

That flexibility is what I wanted from the package.

Final thoughts

There are already good React color picker libraries available, and ChromaPanel is not meant to replace every one of them.

Its focus is different.

It is for applications that need several ways to work with color but still want one consistent React API.

If you need a React color picker with a color wheel, RGB and HSL sliders, palettes, image color extraction, an eyedropper, gradients, modern CSS colors, TypeScript support, accessibility, and zero runtime dependencies, ChromaPanel may be worth trying.

The project is open source and released under the MIT license.

If you use it in a project, find a problem, or have an idea for something that could make the React color picker better, feedback and contributions are welcome.

Top comments (0)