A straightforward utility for merging CSS class names in React & Tailwind and other JavaScript projects.
- We Stand with Palestine
- Production Considerations
- Installation
- Usage
- Workflow To Minimize Typing Strain
- Type Definitions (of Exported Functions)
- Accepted Arguments
- Console Warning
- Conditionally Include Class Names
- Using
mergeClassNamesDebugger
And The Built-in Browser Debugger To Find And Fix Warnings - Strategies To Ensure Correct Arguments Are Sent to
mergeClassNames
- Testing
- Source Code (Partial)
- Misc.
- License
In developing this package, I prioritized code readability, strict input handling, and enhanced developer experience. Consequently, performance and features were not the primary focus. If you are considering this package for production, you may also want to explore clsx
: https://www.npmjs.com/package/clsx.
pnpm add simple-merge-class-names
yarn add simple-merge-class-names
npm install simple-merge-class-names
-
https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode
-
Or use an equivalent auto code formatter for your IDE.
Import mergeClassNames(...args)
from the package, and use it in your JSX or JavaScript code.
import { mergeClassNames } from "simple-merge-class-names";
const MyComponent = () => {
return (
<div
className={mergeClassNames(
"app",
condition ? "min-h-dvh" : false,
"grid",
"grid-rows-[auto_1fr_auto]",
"outline"
)}
>
Hello, world!
</div>
);
};
Or for debugging purposes to fix console warnings:
- Open the Browser's Developer Tools and
- Use
mergeClassNamesDebugger
import { mergeClassNamesDebugger } from "simple-merge-class-names";
const MyComponent = () => {
return (
<div
className={mergeClassNamesDebugger(
"app",
condition ? "min-h-dvh" : false,
"grid",
"grid-rows-[auto_1fr_auto]",
"outline"
)}
>
Hello, world!
</div>
);
};
-
Have
Prettier
installed -
Have
Editor: Word Wrap
enabled in VS Code:-
Open Settings (UI)
βEditor: Word Wrap
βon
-
Or
Open User Settings (JSON)
and add this entry:"editor.wordWrap": "on"
-
-
Use single quotes (') for class names, often a single key press on many keyboards.
-
Save the file (Ctrl+S), which activates
Prettier
to auto-format the file, it will:- Replace single quotes with double quotes.
- Neatly arrange each class name on a new line.
mergeClassNames: (...args: (string | false)[]) => string;
mergeClassNamesDebugger: (...args: (string | false)[]) => string;
Both mergeClassNames
and mergeClassNamesDebugger
always return a string.
- If no inputs are provided (e.g.
mergeClassNames()
) or if invalid inputs are given (e.g.mergeClassNames(undefined, " ")
), an empty string is returned:""
.
mergeClassNames(...args)
and mergeClassNamesDebugger(...args)
only accept the following arguments:
-
Strings that are not empty, and are not whitespace (e.g.
"app"
,"min-h-dvh"
," grid "
) -
The boolean value
false
Any other input is considered an invalid argument and will be ignored, resulting in a matching warning being logged. Invalid argument types include:
- Empty strings (
""
), - Whitespace combinations (e.g.
" "
,"\n"
," \n\t "
, etc...),, null
,undefined
,- Numbers,
- Objects,
- Arrays
Whenever invalid arguments are passed to mergeClassNames
, they are not silently ignored, as this can lead to subtle bugs and increase technical debt. Instead, a console.warn
is shown in the Developer Console to notify the developer of a potentially deeper issue that requires attention. For example:
[mergeClassNames] Warning: invalid arguments were provided and ignored:
* Replace "mergeClassNames" with "mergeClassNamesDebugger" without changing any arguments, and open the Developer Console, or attach Debugger (see README.md).
* Expected all arguments to be either strings or value `false`, but got 5 invalid value(s):
[
(1/5): >undefined< of type "undefined",
(2/5): > test < of type "object",
(3/5): >[object Object]< of type "object",
(4/5): >true< of type "boolean",
(5/5): >null< of type "object"
]
* Expected 0 empty strings, but got 2 invalid value(s):
[
(1/2): ><,
(2/2): > <
]
To conditionally include a class name, use the conditional operator as follows:
condition ? "class-name" : false
, withfalse
serving as the fallback value to ensure clear and warning-free code.
This approach is effective because false
will never result in a warning from the function.
Important: Avoid using the short-circuit implicit syntax like this:
condition && "class-name"
, as it can produce falsy values such as0
,""
,undefined
, andnull
, which will lead to warnings being logged.
import { mergeClassNames } from "simple-merge-class-names";
const MyComponent = () => {
return (
<div
className={mergeClassNames(
"app",
condition ? "min-h-dvh" : false,
"grid",
"grid-rows-[auto_1fr_auto]",
"outline"
)}
>
Hello, world!
</div>
);
};
import { mergeClassNamesDebugger } from "simple-merge-class-names";
const MyComponent = () => {
return (
<div
className={mergeClassNamesDebugger(
"app",
condition ? "min-h-dvh" : false,
"grid",
"grid-rows-[auto_1fr_auto]",
"outline"
)}
>
Hello, world!
</div>
);
};
mergeClassNamesDebugger
is a drop-in replacement for mergeClassNames
but with the added benefit that it will activate the built-in debugger inside browsers like FireFox, Chrome, Safari and even VS Code if configured properly.
This built-in JavaScript feature gained wide-spread support from major browsers around 2012, allowing you to access it with minimal effort. To utilize it, simply follow these two steps:
- Open the Browser's Developer Tools to inform the JavaScript engine that the debugger is enabled.
- Replace
mergeClassNames
withmergeClassNamesDebugger
without altering any of the provided arguments.
When the debugger is enabled (i.e. Browser's Developer Tools is open) and an invalid argument such as undefined
or " "
is passed to mergeClassNamesDebugger
, the JavaScript engine will automatically pause execution and highlight the invalid argument. You simply need to select the offending component (e.g. Container.jsx
) from the Call Stack.
When the debugger is active, it will appear as shown in this screenshot (in Firefox):
- Use the conditional operator to conditionally including class names:
import { mergeClassNames } from "simple-merge-class-names";
const MyComponent = () => {
return (
<div
className={mergeClassNames(
"app",
condition ? "min-h-dvh" : false,
"grid",
"grid-rows-[auto_1fr_auto]",
"outline"
)}
>
Hello, world!
</div>
);
};
This project uses Vitest
as the test runner for fast and modern testing.
git clone https://github.com/new-AF/simple-merge-class-names
cd simple-merge-class-names
pnpm install
pnpm test
pnpm test:watch
/**
* mergeClassNames - A straightforward utility for merging CSS class names in React + Tailwind, and other JavaScript projects.
*
* @license AGPL-3.0
* Copyright (C) 2025 Abdullah Fatota
*
* ...
*/
const mergeClassNamesCore = ({ args, activateDebugger }) => {
const space = "\x20"; // ASCII code for a single space character (" "), decimal 32
const [_, nonFalseValues] = partition(args, isValueFalse); // ignore all false values used for conditional class inclusion
const [strings, nonStrings] = partition(nonFalseValues, isTypeString);
const [emptyStrings, nonEmptyStrings] = partition(strings, isEmptyString);
const trimmed = nonEmptyStrings.map((val) => val.trim());
const className = trimmed.join(space);
/* Don't silently ignore invalid input, explicitly disclose them as it may indicate a bigger problem */
warnInvalidArguments({ nonStrings, emptyStrings, activateDebugger });
return className;
};
export const mergeClassNames = (...args) =>
mergeClassNamesCore({ args, activateDebugger: false });
export const mergeClassNamesDebugger = (...args) =>
mergeClassNamesCore({ args, activateDebugger: true });
This package aims to improve code readability and developer experience in React & Tailwind projects by enforcing strict input handling. It logs warnings for invalid arguments, helping developers catch and fix underlying issues early.
While writing class names as separate strings may seem tedious, the workflow reduces friction and the overall process results in more readable and maintainable code in contrast to using single long strings:
const MyComponent = () => {
return (
<div className="app min-h-dvh grid grid-rows-[auto_1fr_auto] outline">
Hello, world!
</div>
);
};
I wanted to name the package mergeClassNames
to reflect the exported function, but the NPM Package Registry doesn't allow capital letters, only lower case and dash characters.
In addition there was already a package named merge-class-names
but it is no longer maintained (and the developer recommends clsx
instead).
This project is licensed under the AGPL-3.0 License. See LICENSE.txt
for full details.
Enjoy π