mrkeyoor.com_
Wed 23 Sept 00:37 UTC
npmWeb Frontendupdated 22 Sept 2026

moo-color review

moo-color 2.0.0 is an immutable TypeScript color class that parses hex, named colors, transparent, RGB, HSL, HWB, HSV, and CMYK. It converts between those models, formats CSS strings, adjusts channels, mixes colors, and calculates WCAG 2.1 relative luminance and contrast. Version 2 rewrote the package in TypeScript, raised the Node floor to 18, removed `setColor`, and changed mutating methods to return new instances. Our install supplied declarations and working ESM and CommonJS entries; the measured browser import was 4.4 KB gzipped.

Verdict

Our moo-color 2.0.0 install took 1 second and produced a 4.4 KB gzipped browser bundle with bundled types, making it a sensible small choice for RGB, HSL, HWB, HSV, and CMYK work. Choose Culori when current CSS color spaces or perceptual color math enter the requirements.

We installed it

Lab card: what happened when we installed moo-colorScreenshot of moo-color documentation
Install✓ · 1s2 packages on disk · 1 MB
ImportESM import works · require() works · ESM package with exports map
Browser4.4 KBgzipped (12.4 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does moo-color install cleanly?

Yes. In a fresh container with an empty cache, npm install moo-color finished in 1 seconds, leaving 2 packages and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does moo-color add to a browser bundle?

4.4 KB gzipped (12.4 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does moo-color work with both ESM and CommonJS?

Yes. Both import 'moo-color' and require('moo-color') worked in Node 22 in our run. The package is published as ESM with an exports map.

Does moo-color include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

moo-color or culori: which should you use?

culori: Use it for Lab, LCH, OKLab, OKLCH, gamut mapping, interpolation, and a function-oriented color API. Our moo-color 2.0.0 install took 1 second and produced a 4.4 KB gzipped browser bundle with bundled types, making it a sensible small choice for RGB, HSL, HWB, HSV, and CMYK work.

When should you not use moo-color?

The product accepts Lab, LCH, OKLab, OKLCH, color(), or relative color syntax; version 2 does not list those spaces

API stability3/5Version 2.0.0 has a consistent immutable class surface, but it deliberately broke several v1 assumptions. Manipulation methods, `setAlpha`, and `changeModel` now return new instances; `setColor` is gone; the random-argument type changed; and Node 18 is the minimum. The changelog and rewritten docs identify those changes, which helps migration, but an existing application must inspect every ignored return value instead of trusting a compiler-only upgrade.
Docs4/5The README shows ESM, CommonJS, and browser-global loading plus accepted formats, immutable manipulation, formatting, WCAG contrast, and random color creation. Linked API pages document methods and data shapes, and the changelog lists version 2 breaks. Important operational limits remain easy to miss: unsupported Color 4 syntax is not gathered in one place, alpha is not composited for contrast, the 4.5 helper threshold covers normal text only, and broad input string types still allow runtime parse failures.
Maintenance4/5The repository is unarchived, was pushed on 2026-06-19, and reports 3 open issues and pull requests combined. Version 2.0.0 arrived in 2026 with a TypeScript rewrite, immutable operations, corrected WCAG luminance, updated builds, and a Node 18 floor. GitHub shows only 4 stars, so the bus factor and review pool appear small even though current maintenance work is concrete. The release is fresh enough to warrant watching early 2.x issue reports.
Ecosystem3/5The npm endpoint counted 3,326,508 downloads in the latest completed week. The package publishes ESM, CommonJS, IIFE, and declaration files and depends only on `color-name`, which makes it easy to embed in varied toolchains. GitHub has 4 stars and the project documents no plugins, framework adapters, visualization scales, or external extension points. Its download volume is likely driven heavily by transitive use, while Culori and Chroma have broader examples for advanced color work.

Use it if

  • One small immutable object should cover conventional CSS colors plus HSV and CMYK working values
  • Code needs WCAG 2.1 luminance and contrast ratios alongside parsing and formatting
  • The package must load through ESM, CommonJS, or a direct browser script while sharing one API
  • A TypeScript project wants bundled declarations for color objects and model data
Skip it if

Setup reality

Our install of moo-color 2.0.0 finished in 1 second. It left 2 packages and 1 MB on disk; moo-color itself was 284 KB unpacked with 1 direct dependency and no peer dependencies. npm audit found 0 known vulnerabilities. The package requires Node 18 or newer, uses ESM with an exports map, and loaded through both ESM import and CommonJS require. TypeScript declarations were bundled. Our esbuild browser run measured 12.4 KB minified and 4.4 KB gzipped.

No credentials, config files, or native compilation are involved. Import MooColor, then construct it from a supported string or color-data object. Invalid user strings throw during construction, and the package's broad string types cannot prove validity before runtime. Wrap untrusted input in try/catch. Modern CSS strings such as OKLCH need a different parser.

Version 2's migration trap is immutability. Calls such as color.lighten(10), color.setAlpha(0.5), and color.changeModel('hsl') leave the original untouched; assign or chain the returned instance. Replace the removed setColor(next) pattern with new MooColor(next). Conversions often pass through RGB, so repeated cross-model edits can introduce rounding differences.

The WCAG helpers calculate relative luminance and a contrast ratio, and isContrastEnough checks the 4.5 normal-text threshold. It does not choose the 3.0 large-text or 7.0 AAA thresholds for you. Alpha also needs manual compositing against the rendered background before a contrast decision. The IIFE build exposes a browser global, while module bundlers should use the package exports.

Patterns

Catch an invalid color string parse-input

import { MooColor } from 'moo-color';

function parseColor(input: string) {
  try { return new MooColor(input); }
  catch { return null; }
}

Version 2 throws during construction for unsupported input. Its TypeScript string types do not replace this runtime check.

Format one parsed color format-output

const color = new MooColor('rgba(255, 128, 0, 0.5)');

console.log(color.toHex());
console.log(color.toRgb('percent'));
console.log(color.toHsl());
console.log(color.toHwb());

An alpha below 1 produces alpha-bearing output such as eight-digit hex, rgba, or hsla where that formatter supports it.

Keep immutable adjustments together chain-edits

const base = new MooColor('hsl(210, 60%, 40%)');
const accent = base.lighten(15).saturate(10).rotate(20);

console.log(base.toHsl());
console.log(accent.toHsl());

Every manipulation in 2.0.0 returns a new instance; `base` remains unchanged.

Assign version 2 return values migrate-mutation

let color = new MooColor('#336699');
color = color.lighten(10);
color = color.setAlpha(0.8);

Ignoring either return value leaves `color` unchanged. This is the common v1 migration failure.

Inspect converted HSL channels read-model-data

const color = new MooColor('#ff8000');
const hsl = color.getColorAs('hsl');

console.log(hsl.model, hsl.values, hsl.alpha);

`getColorAs` returns copied data, so editing its values array does not mutate the MooColor instance.

Calculate normal-text contrast check-contrast

const foreground = new MooColor('#1f2937');
const background = new MooColor('#ffffff');

const ratio = foreground.contrastRatioWith(background);
const passesNormalAA = foreground.isContrastEnough(background);

`isContrastEnough` uses 4.5. Apply 3.0 for qualifying large text or 7.0 for AAA according to your own rule.

Mix with an explicit weight mix-colors

const red = new MooColor('red');
const blue = new MooColor('blue');

const mostlyRed = MooColor.mix(red, blue, 75);
const mostlyBlue = red.mix(blue, 75);

Static mix weights its first color, while instance mix weights the argument. Read the 75 percent from the correct side.

Use version 2 from CommonJS load-commonjs

const { MooColor } = require('moo-color');

const color = new MooColor('cmyk(0%, 100%, 100%, 0%)');
console.log(color.toRgb());

The CommonJS entry worked in our Node 22 check. Package metadata requires Node 18 or newer.

Alternatives

PackageRegistryPick it when
culorinpmUse it for Lab, LCH, OKLab, OKLCH, gamut mapping, interpolation, and a function-oriented color API.
chroma-jsnpmUse it when chart scales, domains, interpolation modes, and palette generation drive the requirement.
colornpmUse it for another immutable chainable object with a larger established user base.
tinycolor2npmUse it when legacy browser support or tinycolor-compatible parsing matters more than current TypeScript design.

More web frontend guides

postcss · react · react-dom · tailwindcss · htmlparser2 · tailwind-merge · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.