mrkeyoor.com_
Sat 08 Aug 17:43 UTC
npmUtilsupdated 08 Aug 2026

colorjs.io

Color.js is a dependency-free JavaScript color engine created by CSS Color specification editors. It parses CSS Color 4 syntax, converts among a wide set of SDR and HDR spaces, performs chromatic adaptation and real gamut mapping, computes several Delta E and contrast formulas, and builds perceptual gradients. The default Color class offers a convenient object API; a separate procedural entry and direct source imports let performance-sensitive code load only required functions and spaces. It runs in browsers and Node and ships TypeScript declarations.

Verdict

The serious choice when color correctness, modern spaces, and gamut behavior are product requirements. It is unnecessary weight and conceptual scope for ordinary hex and HSL manipulation.

API stability3/5The Color object consistently exposes parsing, conversion, set operations, interpolation, contrast, and Delta E, while each method also has a static form and most have procedural equivalents. However, the package remains at 0.7.1, its large color-space registry continues to track evolving CSS Color specifications, and pre-1.0 releases cannot offer the same compatibility expectation as a mature 1.x line. Pin versions and cover numeric output with fixtures.
Docs5/5The official site separates installation, color objects, manipulation, output, interpolation, gamut mapping, color difference, adaptation, procedural use, and a generated API reference. The README gives executable examples and makes scientific choices visible instead of presenting one unexplained result. The breadth can overwhelm developers who only know RGB, but the documentation provides the definitions and alternatives needed to make deliberate decisions.
Maintenance5/5Version 0.7.1 was published July 24, 2026 and the repository was pushed August 7, 2026, one day before this guide. GitHub reports 94 open issues and pull requests on an active, non-archived repository with 2,284 stars. The maintainer list includes CSS Color specification editors and a broader grassroots team, and the codebase ships current declarations, modular exports, source maps, and extensive space implementations.
Ecosystem4/5The npm download API reports 7,402,908 downloads in the latest week, and the README names Sass, Open Props, axe, and several color tools among dependents. Support spans common CSS formats, wide gamut, HDR, perceptual spaces, and multiple scientific methods, with browser and Node builds. The audience is specialized, and lighter libraries have more mindshare for routine UI color manipulation.

Use it if

  • You need correct conversion among OKLCH, Lab, Display P3, Rec.2020, HDR, XYZ, and other color-science spaces
  • A design or accessibility tool needs explicit Delta E, contrast, gamut mapping, chromatic adaptation, or perceptual interpolation methods
  • You must parse and serialize modern CSS Color 4 formats before every target browser supports them natively
  • You want both a readable Color object and a tree-shakable procedural API for hot or size-sensitive paths
Skip it if

Setup reality

npm install colorjs.io has no runtime dependencies and exposes both ESM and CommonJS builds with bundled types, but choosing the import matters. import Color from 'colorjs.io' registers the large set of spaces and methods and measures about 32.4 KB gzipped. For a smaller browser bundle, use the procedural colorjs.io/fn entry or explicit colorjs.io/src/* modules, then import and register only the spaces and functions you need; that is more ceremony and makes missing registrations a runtime concern. Type declarations require TypeScript 5.0. A plain browser script can use dist/color.global.js, while native browser imports require script type=module. Parsing a CSS color does not mean the browser can display that syntax or gamut. display() consults browser support and returns a String object carrying the actual converted color; in Node it behaves much like serialization because there is no browser support matrix. Wide-gamut colors can sit outside sRGB, so decide whether to preserve coordinates, map them with toGamut, or serialize with inGamut disabled. That decision changes visible output and should be tested with real design fixtures. Color science also brings policy choices: interpolation space, hue arc, Delta E formula, contrast algorithm, white point, and gamut-mapping method are not interchangeable defaults. The object API includes mutable setters and toGamut mutates its receiver; clone shared colors before changing them. The package can parse CSS Color 4 literals itself, but CSS variables, calc expressions, relative colors, and color-mix resolution depend on a DOM context. Teams building simple theme toggles often do not need this much scope, while color editors and specification-facing tools do.

Patterns

Parse modern CSS color syntaxparse-css-color

import Color from 'colorjs.io'

const accent = new Color('oklch(72% 0.18 250 / 0.9)')
console.log(accent.spaceId, accent.coords, accent.alpha)

Color.js parses CSS Color 4 literals even when the current browser cannot display that syntax. Parsing does not imply in-gamut output.

Construct a color from a space and coordinatesconstruct-from-coordinates

const p3Green = new Color('p3', [0, 1, 0], 0.9)
const equivalent = new Color({
  space: 'p3',
  coords: [0, 1, 0],
  alpha: 0.9,
})

Coordinate ranges and units depend on the selected space. Values may be valid numbers while still falling outside a target display gamut.

Convert between color spacesconvert-color-space

const source = new Color('slategray')
const oklch = source.to('oklch')
console.log(oklch.coords)
console.log(oklch.toString({ precision: 4 }))

to returns a converted Color. It does not guarantee that the result fits sRGB or another eventual output gamut.

Inspect out-of-gamut coordinatesserialize-without-clipping

const wide = new Color('color(display-p3 0 1 0)')
const srgb = wide.to('srgb')

console.log(srgb.toString())
console.log(srgb.toString({ inGamut: false, precision: 5 }))

Default serialization maps or clips for valid output. inGamut:false preserves converted coordinates, which can lie outside the nominal range.

Map a wide-gamut color into sRGBmap-to-output-gamut

const wide = new Color('color(display-p3 0 1 0)')
const srgb = wide.clone().toGamut({
  space: 'srgb',
  method: 'css',
})
console.log(srgb.toString())

toGamut mutates the Color, so clone first when the original is still needed. Gamut mapping is a visual policy, not a lossless conversion.

Produce a color the current browser can displaydisplay-browser-supported-color

const color = new Color('color(display-p3 0.2 0.8 0.4)')
const output = color.display({ precision: 4 })
button.style.backgroundColor = String(output)
console.log(output.color.spaceId)

display returns a String object with the converted Color on output.color. In Node there is no browser support detection, so behavior is close to serialization.

Adjust lightness and chroma on a cloneadjust-coordinates

const base = new Color('slategray')
const adjusted = base.clone().set({
  'oklch.l': value => Math.min(1, value + 0.08),
  'oklch.c': value => value * 1.15,
})
console.log(adjusted.to('srgb').toString())

set mutates and returns the receiver. Prefix coordinates with a space when the Color itself is currently stored in a different space.

Mix two colors in OKLCHmix-perceptually

const start = new Color('#ff3b30')
const middle = start.mix('#007aff', 0.5, {
  space: 'oklch',
  outputSpace: 'srgb',
})
console.log(middle.toString())

Interpolation space changes the path and midpoint. Specify it rather than assuming RGB interpolation is visually appropriate.

Generate perceptually limited gradient stepsbuild-color-scale

const steps = new Color('oklch(85% 0.12 100)').steps(
  'oklch(35% 0.16 280)',
  { space: 'oklch', outputSpace: 'srgb', steps: 7, maxDeltaE: 4 }
)
const cssColors = steps.map(color => color.toString())

steps is a minimum when maxDeltaE requires more intermediate colors. The resulting array can therefore be longer than the requested count.

Create a reusable color rangecreate-interpolation-function

const range = new Color('p3', [0, 1, 0]).range('red', {
  space: 'lch',
  outputSpace: 'srgb',
})

const quarter = range(0.25)
const midpoint = range(0.5)

Values between 0 and 1 interpolate. The range function also accepts values outside that interval and extrapolates, which may create unexpected colors.

Measure perceptual difference with Delta E 2000compare-color-difference

const expected = new Color('lab(60% 20 30)')
const measured = new Color('lab(61% 18 31)')
const difference = expected.deltaE2000(measured)
console.log(difference)

Delta E methods are not interchangeable. Record the chosen formula with thresholds and test data instead of storing an unexplained number.

Import only procedural conversion piecesuse-procedural-api

import { parse, to, serialize } from 'colorjs.io/fn'

const parsed = parse('oklch(70% 0.15 240)')
const srgb = to(parsed, 'srgb')
const css = serialize(srgb, { precision: 4 })

The procedural API is intended for tree shaking and hot paths. If you import individual src modules instead, required color spaces must also be registered.

Alternatives

PackageRegistryPick it when
culorinpmYou want broad modern color-space support in a functional, tree-shakable API with a smaller default surface
chroma-jsnpmData visualization needs familiar scales, interpolation, and palette helpers more than standards-level CSS color coverage
colordnpmA UI needs compact immutable RGB, HSL, HSV, and plugin-based helpers with a much smaller bundle
tinycolor2npmLegacy or simple applications only need forgiving common-format parsing and basic transformations