{"id":10994,"library":"hast-util-classnames","title":"HAST Utility for Class Names","description":"hast-util-classnames is a utility package within the unified collective, designed to simplify the management and merging of CSS class names on HAST (HTML Abstract Syntax Tree) elements. It provides a programmatic API to concatenate, conditionally include, or remove classes, analogous to popular string-based classname utilities but operating directly on HAST nodes. The package is currently at version 3.0.0, which requires Node.js 16 or higher and is distributed exclusively as an ES module (ESM). New major versions typically coincide with dropping support for unmaintained Node.js versions or significant API changes, ensuring compatibility with current Node.js releases. Its key differentiator is its deep integration with the HAST ecosystem, allowing direct manipulation of `properties.className` arrays on HAST element nodes, which is more robust than string manipulation when working with syntax trees.","status":"active","version":"3.0.0","language":"javascript","source_language":"en","source_url":"https://github.com/syntax-tree/hast-util-classnames","tags":["javascript","unist","hast","hast-util","util","utility","html","classes","classname","typescript"],"install":[{"cmd":"npm install hast-util-classnames","lang":"bash","label":"npm"},{"cmd":"yarn add hast-util-classnames","lang":"bash","label":"yarn"},{"cmd":"pnpm add hast-util-classnames","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The package became ESM-only in v2.0.0, and Node.js 16+ is required since v3.0.0.","wrong":"const classnames = require('hast-util-classnames');","symbol":"classnames","correct":"import { classnames } from 'hast-util-classnames';"},{"note":"This type, along with `ConditionalMap` and `ConditionalPrimitive`, is useful for TypeScript consumers to correctly type arguments passed to `classnames`.","symbol":"Conditional","correct":"import type { Conditional } from 'hast-util-classnames';"}],"quickstart":{"code":"import {h} from 'hastscript';\nimport {classnames} from 'hast-util-classnames';\n\n// Example 1: Merging class names as an array of strings\nconst mergedClasses = classnames('alpha bravo', {bravo: false, charlie: true}, [123, 'delta']);\nconsole.log('Merged Classes (array):', mergedClasses);\n// Expected output: ['alpha', '123', 'charlie', 'delta']\n\n// Example 2: Modifying classes on a HAST node in place\nconst node = h('p.initial-class', 'Hello, HAST!');\nconsole.log('Original Node:', JSON.stringify(node, null, 2));\n\nconst modifiedNode = classnames(node, 'new-class', {conditional: true, 'old-class': false}, ['another-one']);\nconsole.log('Modified Node:', JSON.stringify(modifiedNode, null, 2));\n/*\nExpected output (simplified):\n{\n  \"type\": \"element\",\n  \"tagName\": \"p\",\n  \"properties\": {\"className\": [\"initial-class\", \"new-class\", \"conditional\", \"another-one\"]},\n  \"children\": [{\"type\": \"text\", \"value\": \"Hello, HAST!\"}]\n}\n*/","lang":"typescript","description":"Demonstrates both ways to use `classnames`: merging an array of strings and modifying a HAST node's `className` property in place."},"warnings":[{"fix":"Upgrade your Node.js environment to version 16 or newer to ensure compatibility.","message":"Version 3.0.0 and above now require Node.js 16 or higher. Older Node.js environments are no longer supported.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Update your import statements from `require('hast-util-classnames')` to `import { classnames } from 'hast-util-classnames';` and ensure your project is configured for ESM.","message":"The package is now exclusively an ES module (ESM) since version 2.0.0. CommonJS `require()` statements will fail.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Only use the documented `classnames` export. Refactor any code that previously relied on internal paths to use the public API.","message":"The `exports` field in `package.json` was changed in v3.0.0. Directly importing non-public APIs or internal paths is no longer supported and will likely break.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Be mindful of the function's signature and return type. If you intend to get a list of classes without modifying a node, do not pass a `Node` as the first argument. If you intend to modify a node, ensure you pass an `Element` node first.","message":"The `classnames` function has two distinct behaviors based on its first argument. If the first argument is a HAST `Node` (specifically an `Element`), it modifies that node's `properties.className` in place and returns the node. If the first argument is not a node (i.e., it starts with `Conditional` arguments), it returns a new `Array<string>` of merged classes.","severity":"gotcha","affected_versions":"*"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Switch to ES module import syntax: `import { classnames } from 'hast-util-classnames';`","cause":"Attempting to import `hast-util-classnames` using CommonJS `require()` syntax.","error":"ERR_REQUIRE_ESM"},{"fix":"Ensure you are using a named import `import { classnames } from 'hast-util-classnames';` and that your Node.js version is 16 or higher for v3.0.0+.","cause":"This error typically occurs if the package is incorrectly imported (e.g., attempting a default import `import classnames from '...'`) or if an outdated Node.js version (pre-16) is used with v3.0.0+.","error":"TypeError: classnames is not a function"}],"ecosystem":"npm"}