Chroma Panel

Search documentation

Find a page or section

Install it, import the stylesheet in your entry file.

This page sets up the React color picker with Vite, from the install to a working picker in App.tsx. There is no plugin to add and no configuration to change. The package ships ESM, so Vite resolves it directly.

Install

npm install chroma-panel

react and react-dom are peer dependencies and the package has no dependencies of its own, so nothing else is pulled in.

Import the stylesheet

The panel injects its stylesheet from an effect. In a client-rendered Vite app that happens before you see anything, so the import is optional. Import it yourself when you want the CSS in your build output rather than in a <style> tag, for example under a strict Content Security Policy.

// src/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
 
import "chroma-panel/style.css";
import "./index.css";
 
import App from "./App";
 
const root = document.getElementById("root");
 
if (root !== null) {
  createRoot(root).render(
    <StrictMode>
      <App />
    </StrictMode>
  );
}

Once you import it yourself, pass injectStyles={false} so the panel does not write the tag as well. It does not make your bundle smaller — the CSS is in the module either way. The other ways to load the CSS are in theming.

A picker in App.tsx

// src/App.tsx
import { useState } from "react";
import { ColorInput, type ColorChangeResult } from "chroma-panel";
 
export default function App() {
  const [color, setColor] = useState<string>("#3366cc");
 
  const handleChange = (result: ColorChangeResult): void => {
    setColor(result.hex);
  };
 
  return (
    <main>
      <ColorInput value={color} onChange={handleChange} injectStyles={false} />
      <p style={{ color }}>{color}</p>
    </main>
  );
}

onChange fires continuously while you drag. Use onChangeComplete for anything that costs something, such as saving or a network call — see controlled and uncontrolled.

If you use Tailwind

The package ships its rules inside @layer chroma-panel. An undeclared layer sorts after Tailwind's, which would let the panel's rules beat your utility classes. Import the stylesheet from your CSS file and declare the order there instead of importing it in main.tsx:

/* src/index.css */
@import "tailwindcss/theme.css" layer(theme);
@import "tailwindcss/preflight.css" layer(base);
@import "chroma-panel/style.css";
@import "tailwindcss/utilities.css" layer(utilities);

Styling with Tailwind explains why that order is the one that works, and which class names each part of the panel takes.

Only the modes you need

Importing chroma-panel registers all five modes: wheel, sliders, palettes, image and pencils. Import the shell from chroma-panel/panel and add the modes yourself to ship less.

import { ChromaPanel } from "chroma-panel/panel";
import "chroma-panel/wheel";
 
<ChromaPanel modes={["wheel"]} />;
What you importAdded to your app
all five modes22.2 kB
shell plus one mode14.1 kB

Both figures are gzipped, with React external, measured as the increase in a Vite production build.

Import modes for the side effect

A mode entry point registers itself when it loads. Write import "chroma-panel/wheel", not a named import, or the bundler may drop it.

Every subpath, including chroma-panel/core for the color engine without React, is listed under entry points.