A className syntax-sugar plugin designed for React that automatically converts static array or object forms of className in JSX into clsx calls at compile time, eliminating the need for manual imports or writing, and making style composition effortless.
Before doing so, make sure that clsx is installed or another available
classNamehandler exists for your project.
- 🔌 Automatically injects
clsx, removing the need for repeated imports. - ⚙️ Customizable imports: supports
importName/importSource, adaptable to various project setups. - 🧩
strictmode can match*ClassNameattributes, ideal for component libraries or design system conventions. - 🎨 Unifies team
classNameformatting. - 🎯 Supports
@clsx-ignore-lineand@clsx-ignore-filefor precise control over transformations. - 💠
TailwindCSSfriendly: arrays naturally organize utility classes by semantics, breakpoints, and states. - 📚 Fully compatible with
TypeScriptandReact JSX runtime(React >= 17 / TS >= 4.1).
npm
npm i babel-plugin-clsx -Dyarn
yarn add babel-plugin-clsx -Dpnpm
pnpm add babel-plugin-clsx -DAdd a Babel configuration to automatically apply clsx when className is a static array or static object.
{
"plugins": ["clsx"]
}Your code
<div className={['c1', 'c2']} />;
<div className={{ c1: true, c2: true }} />;After compilation
import _clsx from 'clsx';
<div className={_clsx('c1', 'c2')} />;
<div className={_clsx({ c1: true, c2: true })} />;If you want variable values to be automatically applied with clsx, place them in a static array.
Your code
const cs1 = ['c1', 'c2'];
const cs2 = { c3: true, c4: true };
<div className={[cs1]} />;
<div className={[cs2]} />;
<div className={[handler('c5', 'c6')]} />;After compilation
import _clsx from 'clsx';
const cs1 = ['c1', 'c2'];
const cs2 = { c3: true, c4: true };
<div className={_clsx(cs1)} />;
<div className={_clsx(cs2)} />;
<div className={_clsx(handler('c5', 'c6'))} />;options.[ strict | importName | importSource ]
interface Options {
/**
* @default true
*/
strict?: boolean;
/**
* @default 'default'
*/
importName?: string;
/**
* @default 'clsx'
*/
importSource?: string;
}Strict mode is turned on by default, and you can turn it off if you want to add clsx to any attribute suffixed by className.
Add the babel configuration
{
"plugins": [
[
"clsx",
{
"strict": false
}
]
]
}Your code
<Component className={['c1', 'c2']} headerClassName={['c3', 'c4']} footerClassName={['c5', 'c6']} />After compilation
import _clsx from 'clsx';
<Component
className={_clsx('c1', 'c2')}
headerClassName={_clsx('c3', 'c4')}
footerClassName={_clsx('c5', 'c6')}
/>;If your custom import source does not have a default export available, you can specify the import name with importName.
Add the babel configuration
{
"plugins": [
[
"clsx",
{
"importName": "customClsx"
}
]
]
}Your code
<div className={['c1', 'c2']} />After compilation
import { customClsx as _clsx } from 'clsx';
<div className={_clsx('c1', 'c2')} />;clsx is the default supported library, but you can use importSource to substitute it with another library if needed.
Add the babel configuration
{
"plugins": [
[
"clsx",
{
"importSource": "@/utils/custom-clsx"
}
]
]
}Your code
<div className={['c1', 'c2']} />After compilation
import _clsx from '@/utils/custom-clsx';
<div className={_clsx('c1', 'c2')} />;If you feel that there is an unnecessary transformation, you can add a comment so that it is ignored during the transformation.
You can ignore the conversion of this line by adding a comment above.
Your code
<div className={['c1', 'c2']} />;
<div
// @clsx-ignore-line
className={['c3', 'c4']}
/>;After compilation
import _clsx from 'clsx';
<div className={_clsx('c1', 'c2')} />;
<div
// @clsx-ignore-line
className={['c3', 'c4']}
/>;You can omit the conversion of the entire file by adding a comment at the top of the file.
Your code
// @clsx-ignore-file
<div className={['c1', 'c2']} />;
<div className={['c3', 'c4']} />;After compilation
// @clsx-ignore-file
<div className={['c1', 'c2']} />;
<div className={['c3', 'c4']} />;
⚠️ To usebabel-plugin-clsxin a TypeScript project, React >= 17 and TypeScript >= 4.1 are required.
A few adjustments intsconfig.jsonare needed to ensure TypeScript recognizes the JSX support provided by the plugin.
To make babel-plugin-clsx work correctly in a TypeScript project, configure the corresponding JSX runtime in compilerOptions.paths.
| JSX Setting | Paths Configuration | Use Case |
|---|---|---|
"react" |
"react": ["node_modules/babel-plugin-clsx/react"] |
Classic JSX runtime, for jsx: react |
"react-jsx" |
"react/jsx-runtime": ["node_modules/babel-plugin-clsx/jsx-runtime"] |
New JSX transform, for jsx: react-jsx |
"react-jsxdev" |
"react/jsx-dev-runtime": ["node_modules/babel-plugin-clsx/jsx-dev-runtime"] |
New JSX transform (development mode), for jsx: react-jsxdev |
If your project only has global JSX definitions, you need to map the globalThis.JSX to the local React.JSX so that TypeScript can correctly recognize it:
{
"compilerOptions": {
+ "types": ["babel-plugin-clsx/jsx-scope"]
}
}If your project is missing the 'react/index' path, add it as follows:
{
"compilerOptions": {
"paths": {
+ "react/index": ["node_modules/@types/react/index"]
}
}
}| Version Type | Source Code | Live Demo |
|---|---|---|
| react-v19 | ||
| react-jsx-v19 | ||
| react-jsxdev-v19 | ||
| react-v17 | ||
| react-jsx-v17 | ||
| react-jsxdev-v17 |