mrkeyoor.com_
Wed 23 Sept 09:31 UTC
npmWeb Frontendupdated 23 Sept 2026

icss-replace-symbols review

Our browser build of icss-replace-symbols 1.1.0 was 0.9 KB minified and 0.5 KB gzipped. The package does one old CSS Modules linking job: it walks a PostCSS tree and substitutes named tokens inside declaration values and @media parameters. It changes the tree in place, returns no CSS string, and does not rewrite selectors, property names, or other at-rules. Version 1.1.0 is still current; the original repository now redirects to icss-utils, where the maintained replaceSymbols function lives.

Verdict

icss-replace-symbols 1.1.0 installed in 0.5 seconds, occupied 1 MB, and produced a 0.5 KB gzipped browser build in our sandbox, but its repository now redirects to icss-utils. Keep it for an old linker that already relies on this behavior; choose icss-utils for new code.

We installed it

Lab card: what happened when we installed icss-replace-symbolsScreenshot of icss-replace-symbols documentation
Install✓ · 0.5s1 package on disk · 1 MB
ImportESM import works · require() works · CommonJS package
Browser0.5 KBgzipped (0.9 KB minified), bundled with esbuild
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does icss-replace-symbols install cleanly?

Yes. In a fresh container with an empty cache, npm install icss-replace-symbols finished in 0.5s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does icss-replace-symbols add to a browser bundle?

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

Does icss-replace-symbols work with both ESM and CommonJS?

Yes. Both import 'icss-replace-symbols' and require('icss-replace-symbols') worked in Node 22 in our run. The package is published as CommonJS.

Does icss-replace-symbols include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

icss-replace-symbols or icss-utils: which should you use?

icss-utils: Use it for new ICSS work that needs replaceSymbols plus import and export extraction. icss-replace-symbols 1.1.0 installed in 0.5 seconds, occupied 1 MB, and produced a 0.5 KB gzipped browser build in our sandbox, but its repository now redirects to icss-utils.

When should you not use icss-replace-symbols?

You are writing a new ICSS plugin: the old GitHub URL redirects to icss-utils, which exports replaceSymbols alongside import and export helpers

API stability4/5Version 1.1.0 exposes one default tree mutator and a named replaceAll helper, and no later release has changed that surface. The published implementation makes the boundaries easy to verify: declaration values and @media parameters change, while selectors and property names do not. That predictability comes from a frozen package rather than an active compatibility policy, so the score stops short of 5.
Docs2/5The package README identifies both arguments and shows the two locations that receive substitutions. It omits several details visible in the 1.1.0 code: the root is mutated, the default function returns undefined, CommonJS callers receive a .default export, falsy replacements are skipped, and dots count as token characters. The documented GitHub address also redirects readers to the broader icss-utils project.
Maintenance1/5npm still labels 1.1.0 as current and does not attach a deprecation notice, but the package has no newer release and its original repository redirects to css-modules/icss-utils. The redirected repository was last pushed in January 2023. This usable legacy code has a clear successor and receives no standalone releases, compatibility updates, or direct issue triage.
Ecosystem3/5npm recorded 3,840,229 downloads in the week ending August 24, 2026, which points to substantial use inside existing frontend dependency graphs. The redirected GitHub project has 22 stars, and current ICSS tooling groups this function inside icss-utils. High installation volume therefore says more about old CSS Modules compatibility than about new direct adoption or a large standalone community.

Use it if

  • You maintain a CSS Modules or PostCSS integration that already imports icss-replace-symbols and depends on its exact token matcher
  • You already have a PostCSS root and only need synchronous substitution in declaration values and @media parameters
  • You need the historical behavior where dotted strings, hash values, dimensions, and custom-property-like names can be translation keys
  • You are repairing an old build pipeline and changing the linker dependency would create more risk than keeping this 24 KB package
Skip it if

Setup reality

Our fresh install of icss-replace-symbols 1.1.0 finished in 0.5 seconds. It left 1 package and 1 MB on disk, with 0 direct dependencies, 0 peer dependencies, and 0 audit findings. The package itself is 24 KB unpacked under the ISC license. There is no native build, credential, or configuration step.

The package does not parse CSS. Pass it a PostCSS root that supplies walkDecls and walkAtRules, plus a plain object whose keys are symbols and whose values are replacement strings. It mutates that root and returns undefined. When a processor owns the tree, call it from a PostCSS plugin hook instead of placing the function itself in the plugin array.

Version 1.1.0 is CommonJS without an exports map. Both require() and ESM import loaded on Node 22 in our sandbox, but CommonJS receives the Babel-shaped module and uses .default for the main function. No TypeScript declarations ship with the package, so typed projects need a local declaration or should move to icss-utils.

Matching is lexical rather than CSS-value-aware. The expression accepts word characters plus $, #, hyphen, and dot, so palette.red is one token and a mapping for red will not change its suffix. A replacement runs once at the matched position, not recursively. Falsy replacement values are ignored because the implementation tests the replacement before inserting it.

Patterns

Replace one value token replace-declaration-value

import postcss from 'postcss';
import replaceSymbols from 'icss-replace-symbols';

const root = postcss.parse('.button { color: brandColor }');
replaceSymbols(root, { brandColor: '#2563eb' });
console.log(root.toString());

Version 1.1.0 mutates the PostCSS root and returns undefined.

Replace several tokens in one declaration replace-several-tokens

const root = postcss.parse('.card { box-shadow: offsetX offsetY blur shadowColor }');
replaceSymbols(root, {
  offsetX: '0',
  offsetY: '2px',
  blur: '8px',
  shadowColor: 'rgb(0 0 0 / 20%)',
});
console.log(root.toString());

Each mapped token in the declaration value is handled during the same synchronous walk.

Expand an @media token replace-media-query

const root = postcss.parse('@media small { .grid { display: grid } }');
replaceSymbols(root, { small: '(max-width: 599px)' });
console.log(root.toString());

Only @media parameters are visited; @supports and @container parameters stay unchanged.

Wrap the helper as a PostCSS 8 plugin wrap-postcss-eight

const translations = { gapToken: '1rem' };
const linker = {
  postcssPlugin: 'local-icss-linker',
  Once(root) {
    replaceSymbols(root, translations);
  },
};

const result = await postcss([linker]).process('.stack { gap: gapToken }', { from: undefined });

The package export is a tree helper, not a PostCSS plugin object.

Load the Babel default export with require load-from-commonjs

const postcss = require('postcss');
const replaceSymbols = require('icss-replace-symbols').default;

const root = postcss.parse('.badge { background: accent }');
replaceSymbols(root, { accent: 'tomato' });

The CommonJS entry exposes the main function on .default and replaceAll as a named property.

Confirm that only the value changes preserve-selector-and-property

const root = postcss.parse('.brand { brand: brand }');
replaceSymbols(root, { brand: 'renamed' });
console.log(root.toString());
// .brand { brand: renamed }

The class selector and declaration property are outside the package's two tree walks.

Rename a custom property reference replace-custom-property-reference

const root = postcss.parse('.alert { color: var(--danger) }');
replaceSymbols(root, { '--danger': '--color-error' });
console.log(root.toString());

This changes the reference in the value; a declaration named --danger would keep its property name.

Use hash and dimension strings as keys replace-css-literals

const root = postcss.parse('.box { border-color: #f00; margin: 0.5em }');
replaceSymbols(root, { '#f00': 'rebeccapurple', '0.5em': '8px' });
console.log(root.toString());

The 1.1.0 matcher accepts #, $, hyphen, dot, and word characters.

Treat a dotted name as one symbol handle-dotted-symbols

const root = postcss.parse('.item { color: palette.red; background: red }');
replaceSymbols(root, { red: 'green' });
console.log(root.toString());
// .item { color: palette.red; background: green }

A mapping for red does not replace the red suffix of palette.red because the dot belongs to the match.

Account for one-pass substitution avoid-recursive-substitution

const root = postcss.parse('.item { color: primary; background: secondary }');
replaceSymbols(root, { primary: 'secondary', secondary: 'black' });
console.log(root.toString());
// .item { color: secondary; background: black }

Inserted text is not processed again at the same location.

Replace tokens in a standalone string call-replace-all

const { replaceAll } = require('icss-replace-symbols');

const value = replaceAll({ spacing: '12px', ink: '#111' }, '0 spacing ink');
console.log(value);
// 0 12px #111

replaceAll is exported in 1.1.0 even though the README documents only the default tree helper.

Avoid empty-string replacements detect-falsy-replacement

const root = postcss.parse('.item { color: token }');
replaceSymbols(root, { token: '' });
console.log(root.toString());
// .item { color: token }

The implementation checks replacement truthiness, so an empty string does not remove a token.

Alternatives

PackageRegistryPick it when
icss-utilsnpmUse it for new ICSS work that needs replaceSymbols plus import and export extraction.
postcss-modules-valuesnpmUse it when you want a PostCSS plugin for defining and importing values between CSS Modules files.
postcss-modulesnpmUse it when the job is a complete CSS Modules transformation rather than a low-level tree mutation.
postcss-custom-propertiesnpmUse it when standard CSS custom properties describe the values you need to transform.

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.