mrkeyoor.com_
Sat 08 Aug 20:58 UTC
npmWeb Frontendupdated 08 Aug 2026

@ctrl/tinycolor

@ctrl/tinycolor is a TypeScript color parser, converter, and manipulation library descended from tinycolor2. `TinyColor` accepts hex, RGB, HSL, HSV, CMYK, named colors, numbers, and component objects, then formats or modifies them and builds palettes. Separate exports cover ratio inputs, seeded random colors, WCAG 2.0 contrast, readability checks, and foreground selection. It ships CommonJS and tree-shakeable module builds with declarations and no runtime dependencies.

Verdict

A capable, typed all-purpose color utility for UI code, especially when permissive input and tinycolor2-compatible operations are useful. Put validation and cloning wrappers around it; choose a perceptual color library when modern color spaces or visualization-grade interpolation drive the work.

API stability4/5The fork documents its intentional breaks from tinycolor2, including the named TinyColor class, removed default export, standalone utilities, and property-based isValid and format. Within the current API, methods and return shapes are extensive and consistently typed. A major-version migration still deserves attention because import style and helper placement have changed before, and mutation is part of the contract.
Docs5/5The README is unusually complete: it enumerates accepted strings and objects, output methods, alpha behavior, mutation, palette generation, seeded random options, contrast ratios, AA and AAA checks, readable-color fallback, and migration differences from tinycolor2, with executable TypeScript examples. Minor blemishes include a few wording errors and links to older WCAG explanatory material.
Maintenance4/5Version 4.2.0 was published in September 2025, and GitHub reports a push that same month, a non-archived repository, MIT licensing, and 10 open issues and pull requests. That is healthy evidence for a mature utility, though there has not been repository activity in nearly a year and consumers should still watch whether Node and packaging targets advance.
Ecosystem4/5The measured week recorded 4,293,786 npm downloads. The project inherits familiar tinycolor2 concepts while adding TypeScript, module tree shaking, randomColor behavior, CMYK, polyads, and standalone accessibility utilities, and it runs without runtime dependencies. The broader JavaScript color ecosystem is fragmented, and advanced visualization and perceptual workflows still live in tools such as chroma-js.

Use it if

  • You need one typed API to accept several common color formats and normalize output
  • You generate tints, shades, complements, or multi-color palettes in frontend tooling
  • You need WCAG 2.0 contrast ratios and readable foreground selection from a candidate list
  • You are migrating from tinycolor2 and want a maintained TypeScript fork with named exports
Skip it if

Setup reality

Install with npm install @ctrl/tinycolor. Version 4.2.0 has no runtime or peer dependencies, no native build, credentials, global CSS, config, or initialization. It publishes a CommonJS main entry, a tree-shakeable module entry, `sideEffects: false`, and TypeScript declarations; package metadata requires Node 14 or later. Import named exports such as `TinyColor`, `readability`, `isReadable`, `mostReadable`, `fromRatio`, and `random`. There is no default export, which is the first migration surprise for tinycolor2 users, and helpers such as readability and fromRatio are standalone exports rather than static methods on the class. Parsing is intentionally forgiving: optional punctuation and several numeric conventions make user input convenient, but malformed input does not throw. Always inspect the `isValid` property before storing or rendering a user-supplied color because invalid instances continue through other methods as black. `isValid` and `format` are properties, not functions. Modification methods mutate the instance and return it, so clone before deriving variants from a shared base. Saturation and lightness returned by `toHsl()` are fractions even though formatted HSL strings use percentages. Alpha changes output shape, for example `toRgbString()` switches to rgba syntax. For accessible translucent colors, composite with `onBackground()` before checking contrast. The readability helpers implement the documented WCAG 2.0 ratio model and require you to choose AA or AAA plus small or large text; they do not decide typography eligibility for you. Seed `random()` when snapshots or server-rendered output must repeat.

Patterns

Parse a color without accepting invalid blackparse-and-validate

import { TinyColor } from '@ctrl/tinycolor';

const color = new TinyColor(userInput);
if (!color.isValid) throw new Error('Invalid color');
console.log(color.toHexString());

Invalid instances do not throw and behave like black, so check the isValid property before using them.

Normalize supported input to six-digit hexnormalize-hex

import { TinyColor } from '@ctrl/tinycolor';

function normalizeHex(input: string) {
  const color = new TinyColor(input);
  return color.isValid ? color.toHexString() : null;
}

console.log(normalizeHex('rgb(54, 153, 204)')); // #3699cc

toHexString omits alpha; use toHex8String when transparency must survive.

Parse and format an alpha colorpreserve-alpha

import { TinyColor } from '@ctrl/tinycolor';

const color = new TinyColor('rgba(255, 0, 0, 0.5)');
console.log(color.toRgbString());
console.log(color.toHex8String()); // #ff000080

Eight-digit hex places alpha last, and channel rounding can make 0.5 appear as 0x80.

Convert a color to HSL componentsconvert-color-space

import { TinyColor } from '@ctrl/tinycolor';

const hsl = new TinyColor('#ff8000').toHsl();
console.log(hsl); // h, s, l, a
console.log(new TinyColor('#ff8000').toHslString());

toHsl returns saturation and lightness as fractions; toHslString displays percentages.

Create a lighter variant without changing the basederive-without-mutation

import { TinyColor } from '@ctrl/tinycolor';

const base = new TinyColor('#2563eb');
const lighter = base.clone().lighten(15);
console.log(base.toHexString(), lighter.toHexString());

lighten mutates its instance. clone first when the original color is still needed.

Mix two colorsmix-colors

import { TinyColor } from '@ctrl/tinycolor';

const mixed = new TinyColor('#ff00ff')
  .mix('#00ff00', 50)
  .toHexString();
console.log(mixed); // #808080

mix mutates the first TinyColor; the amount is a percentage from 0 to 100.

Generate a tetradic palettegenerate-palette

import { TinyColor } from '@ctrl/tinycolor';

const palette = new TinyColor('#ef4444')
  .tetrad()
  .map((color) => color.toHexString());
console.log(palette);

Combination methods return TinyColor objects, not strings; format each result explicitly.

Calculate a WCAG contrast ratiocalculate-contrast

import { readability } from '@ctrl/tinycolor';

const ratio = readability('#111827', '#ffffff');
console.log(ratio);

The result is a ratio. Passing a threshold depends on text size and the conformance level you target.

Check AA contrast for small textcheck-aa-readability

import { isReadable } from '@ctrl/tinycolor';

const passes = isReadable('#111827', '#ffffff', {
  level: 'AA',
  size: 'small',
});
console.log(passes);

Choose small or large based on the rendered typography; the library cannot infer font size and weight.

Choose black or white foreground textchoose-text-color

import { mostReadable } from '@ctrl/tinycolor';

const foreground = mostReadable('#7c3aed', ['#000', '#fff'], {
  includeFallbackColors: true,
  level: 'AA',
  size: 'small',
});
console.log(foreground.toHexString());

The return value is a TinyColor. includeFallbackColors permits black or white even when they were not candidates.

Composite transparency before checking contrastcomposite-alpha

import { TinyColor, readability } from '@ctrl/tinycolor';

const background = '#ffffff';
const displayed = new TinyColor('rgba(37, 99, 235, 0.5)')
  .onBackground(background);
console.log(readability(displayed, background));

A translucent foreground has no fixed displayed color until its background is known.

Generate repeatable random colorsgenerate-seeded-color

import { random } from '@ctrl/tinycolor';

const color = random({
  seed: 42,
  hue: 'blue',
  luminosity: 'light',
});
console.log(color.toHexString());

Supply an integer seed for deterministic tests or server rendering; an unseeded call is intentionally variable.

Alternatives

PackageRegistryPick it when
colordnpmYou want a smaller immutable core and can add only the color-space plugins your app needs
colornpmYou prefer an immutable chainable API with CSS color parsing and conversion
chroma-jsnpmYou need scales, interpolation, statistics, or perceptual color spaces for visualization
tinycolor2npmYou must preserve the original tinycolor2 default export and legacy API in an existing codebase