Image Color Palette Generating Plugin - Color Thief

File Size: 1.72 MB
Views Total: 8924
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
   
Image Color Palette Generating Plugin - Color Thief

Color Thief is a vanilla JavaScript library that extracts dominant colors, color palettes, and semantic swatches from images, videos, canvas elements, and Node.js image sources.

You can use it to create image-matched backgrounds, product-card accents, media-player ambient lighting, gallery themes, and upload-preview color tools.

Color Thief Version 3.0 is a complete rewrite that drops the old jQuery dependency. You can now use it straight in the browser, in Node.js, or as a CLI tool.

Features:

  • Extracts the dominant color from image, video, and canvas sources.
  • Generates multi-color palettes sorted by visual dominance.
  • Creates semantic color groups for accents, backgrounds, and text areas.
  • Returns color objects with hex, RGB, HSL, OKLCH, and CSS output.
  • Calculates readable foreground colors and contrast data.
  • Processes live video and canvas sources for reactive UI color updates.

How To Use It:

1. Install Or Include Color Thief

For a browser page on jQueryScript, the CDN version gives the fastest setup path. Color Thief v3 does not need CSS and does not need jQuery.

<script src="https://unpkg.com/colorthief@3/dist/umd/color-thief.global.js"></script>

For a module or bundler project, install the npm package.

npm install colorthief
import { getColorSync, getPaletteSync, getSwatchesSync, observe } from 'colorthief';

For Node.js image files or buffers, install sharp as the image decoder peer dependency.

npm install colorthief sharp

2. Add An Image Source

Color Thief reads pixel data from a loaded image. Add crossorigin="anonymous" when the image comes from another domain and that server supports CORS.

<img
  id="product-photo"
  src="images/headphones.jpg"
  alt="Wireless headphones"
  crossorigin="anonymous"
/>

<div class="product-theme">
  <h2 id="product-title">Wireless Headphones</h2>
  <p id="product-color">Waiting for image color...</p>
</div>

3. Extract The Dominant Color

<script>
  const img = document.getElementById('product-photo');
  const card = document.querySelector('.product-theme');
  const label = document.getElementById('product-color');

  function applyDominantColor() {
    const color = ColorThief.getColorSync(img);

    if (!color) {
      label.textContent = 'No color found.';
      return;
    }

    card.style.backgroundColor = color.css();
    card.style.color = color.textColor;
    label.textContent = color.hex();
  }

  if (img.complete) {
    applyDominantColor();
  } else {
    img.addEventListener('load', applyDominantColor);
  }
</script>

The image must finish loading before extraction. The code checks img.complete first, then waits for the standard load event when the image is still loading.

4. Generate A Color Palette

<img id="gallery-cover" src="images/gallery-cover.jpg" alt="Gallery cover" crossorigin="anonymous" />

<ul id="palette-list"></ul>

<script>
  const cover = document.getElementById('gallery-cover');
  const paletteList = document.getElementById('palette-list');

  function renderPalette() {
    const palette = ColorThief.getPaletteSync(cover, {
      colorCount: 6,
      quality: 10,
      colorSpace: 'oklch'
    });

    if (!palette) return;

    paletteList.innerHTML = palette.map((color) => {
      return `
        <li style="background:${color.css()};color:${color.textColor}">
          ${color.hex()} (${Math.round(color.proportion * 100)}%)
        </li>
      `;
    }).join('');
  }

  cover.complete ? renderPalette() : cover.addEventListener('load', renderPalette);
</script>

This example builds a palette list from one image. colorCount controls the number of colors, quality controls the pixel sampling rate, and colorSpace controls the quantization model.

5. Use Semantic Swatches For UI Roles

<img id="article-image" src="images/editorial.jpg" alt="Editorial cover" crossorigin="anonymous" />

<header id="story-header">
  <h1 id="story-title">Design Notes</h1>
  <p id="story-summary">A palette generated from the cover image.</p>
</header>

<script>
  const articleImage = document.getElementById('article-image');
  const header = document.getElementById('story-header');
  const title = document.getElementById('story-title');
  const summary = document.getElementById('story-summary');

  function applySwatches() {
    const swatches = ColorThief.getSwatchesSync(articleImage);

    if (swatches.DarkMuted) {
      header.style.backgroundColor = swatches.DarkMuted.color.css();
      header.style.color = swatches.DarkMuted.bodyTextColor.css();
    }

    if (swatches.LightVibrant) {
      title.style.color = swatches.LightVibrant.color.css();
    }

    if (swatches.Muted) {
      summary.style.borderColor = swatches.Muted.color.css();
    }
  }

  articleImage.complete ? applySwatches() : articleImage.addEventListener('load', applySwatches);
</script>

Semantic swatches help you map extracted colors to real UI roles. DarkMuted works well for dark panels, LightMuted works well for card backgrounds, and Vibrant works well for visual accents.

6. Observe A Video Or Canvas Source

<video id="promo-video" src="media/promo.mp4" controls muted></video>
<section id="ambient-panel">
  <h2 id="ambient-heading">Live Palette</h2>
</section>

<script>
  const video = document.getElementById('promo-video');
  const panel = document.getElementById('ambient-panel');
  const heading = document.getElementById('ambient-heading');

  const controller = ColorThief.observe(video, {
    throttle: 250,
    colorCount: 5,
    quality: 15,
    onChange(palette) {
      const dominant = palette[0];

      if (!dominant) return;

      panel.style.backgroundColor = dominant.css();
      heading.style.color = dominant.textColor;
    }
  });

  window.addEventListener('pagehide', () => {
    controller.stop();
  });
</script>

observe() watches a video, canvas, or image element and runs onChange with a fresh palette. Call stop() when the component, page, modal, or media player no longer needs updates.

7. Use Color Thief In Node.js

import { getColor, getPalette } from 'colorthief';

const imagePath = './uploads/campaign-banner.jpg';

const dominant = await getColor(imagePath);
const palette = await getPalette(imagePath, {
  colorCount: 5,
  quality: 10
});

console.log('Dominant:', dominant?.hex());
console.log('Palette:', palette?.map((color) => color.hex()));

The async API works in Node.js with file paths and buffers. Use the sync API only for supported browser sources.

8. Use The CLI

npx colorthief-cli photo.jpg
colorthief-cli palette photo.jpg --count 5
colorthief-cli swatches photo.jpg
colorthief-cli photo.jpg --json
colorthief-cli palette photo.jpg --css

The CLI works well for build scripts, static-site color extraction, design-token generation, and quick checks during asset preparation.

All configuration options:

  • colorCount (Number, default: 10): Sets the number of colors for palette extraction. Use values from 2 to 20.
  • quality (Number, default: 10): Sets the pixel sampling rate. 1 samples every pixel. Higher values sample fewer pixels.
  • colorSpace (String, default: 'oklch'): Sets the quantization color space. Accepted values are 'oklch' and 'rgb'.
  • ignoreWhite (Boolean, default: true): Skips pixels that appear white.
  • whiteThreshold (Number, default: 250): Sets the RGB channel threshold for white pixel detection.
  • alphaThreshold (Number, default: 125): Skips pixels below the specified alpha value.
  • minSaturation (Number, default: 0): Skips pixels below the specified HSV saturation value.
  • signal (AbortSignal, default: not specified): Cancels a running async extraction. Async API only.
  • worker (Boolean, default: false): Moves browser async quantization to a Web Worker. Browser async API only.

API Methods:

Extraction Functions

  • getColor(source, options?): Extracts the dominant color. Returns Promise<Color | null>.
  • getColorSync(source, options?): Extracts the dominant color synchronously in the browser. Returns Color | null.
  • getPalette(source, options?): Extracts a palette sorted by dominance. Returns Promise<Color[] | null>.
  • getPaletteSync(source, options?): Extracts a palette synchronously in the browser. Returns Color[] | null.
  • getSwatches(source, options?): Extracts semantic swatches. Returns Promise<SwatchMap>.
  • getSwatchesSync(source, options?): Extracts semantic swatches synchronously in the browser. Returns SwatchMap.
  • observe(source, options): Watches an image, video, or canvas source and sends palette updates to options.onChange.
  • configure(options): Sets a custom pixel loader or custom quantizer for extraction functions.
  • createColor(r, g, b, population, proportion?): Creates a Color object from RGB values and population data.

Color Object Methods

  • rgb(): Returns { r, g, b }.
  • hex(): Returns a hex color string.
  • hsl(): Returns { h, s, l }.
  • oklch(): Returns { l, c, h }.
  • css(format?): Returns a CSS color string. Supported formats are rgb, hsl, and oklch.
  • array(): Returns [r, g, b].
  • toString(): Returns the hex color string.

Color Object Properties

  • textColor: Returns '#ffffff' or '#000000' for readable foreground text.
  • isDark: Returns true when the color is perceptually dark.
  • isLight: Returns true when the color is perceptually light.
  • contrast: Returns contrast data for white, black, and recommended foreground color.
  • population: Returns the relative pixel count from the quantizer.
  • proportion: Returns the sampled-image share for the color as a 0 to 1 value.

Swatches

getSwatches() and getSwatchesSync() return a SwatchMap with six semantic roles.

  • Vibrant: Bright saturated color for primary accents.
  • Muted: Desaturated medium-brightness color for backgrounds.
  • DarkVibrant: Saturated dark color for headers and status bars.
  • DarkMuted: Desaturated dark color for text panels.
  • LightVibrant: Saturated light color for highlights.
  • LightMuted: Desaturated light color for cards and borders.

Each swatch includes these properties.

  • color: The extracted Color object.
  • role: The semantic role name.
  • titleTextColor: Recommended title text color over the swatch.
  • bodyTextColor: Recommended body text color over the swatch.

Observe Options And Controller

  • source: Accepts an HTMLVideoElement, HTMLCanvasElement, or HTMLImageElement.
  • onChange: Required callback. Receives (palette: Color[]).
  • throttle (Number, default: 200): Sets the minimum time between updates in milliseconds.
  • colorCount (Number, default: 5): Sets the number of colors for each observed palette.
  • quality (Number, default: 10): Sets the pixel sampling rate.
  • colorSpace (String, default: 'oklch'): Sets the quantization color space.
  • ignoreWhite, whiteThreshold, alphaThreshold, minSaturation: Reuse the standard filter options.

The returned controller exposes one method.

  • stop(): Stops observation and cleans up listeners and animation-frame work.

Alternatives And Related Resources:

FAQs:

Q: Why does Color Thief return no color from my image?
A: The image may not have finished loading, or the browser may block canvas pixel access for a cross-origin image. Wait for the load event and use crossorigin="anonymous" only when the remote server sends proper CORS headers.

Q: Should I use the sync or async API?

A: Use the sync API for small browser examples and immediate UI updates after an image loads. Use the async API for Node.js, Web Workers, cancellation, large images, or batch extraction.

Q: Does Color Thief work with cross‑origin images?
A: The image must be served with the crossorigin="anonymous" attribute and appropriate CORS headers. Otherwise, the canvas becomes tainted and extraction returns null.

Q: I get an error when importing the module from a CDN. What's wrong?
A: Make sure you use the correct file path: /dist/color-thief.modern.js. The global UMD build (color-thief.global.js) creates a colorthief global variable instead of ESM exports.

Q: The palette has fewer colors than I set in colorCount. Why?
A: Pixels that match the whiteThreshold or fall below minSaturation are filtered out. Lower those thresholds to include more subtle colors.

Q: How do I use Color Thief in a React component?
A: Import the async function inside useEffect. Wait for the image ref to load, then call getColor() and store the result in state. The sync functions also work if you call them inside the load event handler.

Q: Can I stop the live observation started with observe()?
A: Yes. The method returns a controller object with a stop() function. Always call stop() when the source element is removed to release resources.

Changelog:

v3.4.0 (2026-07-03)

  • Wide-gamut (Display P3) support

v3.4.0 (2026-07-03)

  • Wide-gamut (Display P3) support

v3.3.0 (2026-06-11)

  • Adds colorthief CLI with color, palette, and swatches subcommands. Supports --json, --css, and ANSI output formats, stdin piping, multi-file input, and a friendly error message when sharp is not installed.

v2.4.0 (2023-03-02)

  • fix: Use image naturalHeight and naturalHeight

v2.3.2 (2020-07-06)

  • fix: Use image naturalHeight and naturalHeight

v2.3.0 (2019-08-05)

  • feat: Node support. Use color-thief-node.js file in dist folder
  • test: Added simple tests for node env with Mocha and Chai to go alongside the Cypress browser tests
  • build: Discontinue outputting sourcemaps

v2.2.1 (2019-07-23)

  • fix: Remove node version requirement
  • refactor: Create sep repo for quantize lib and import
  • refactor: Use a shared core lib
  • test: Enable other palette count tests post-quantize func updates
  • test: Remove bad test case, colorcount(1)

v2.2 (2019-07-22)

  • Add CommonJS, AMD, and ES6 module support

This awesome jQuery plugin is developed by lokesh. For more Advanced Usages, please check the demo page or visit the official website.