React offers basically zero support for CSS. Personally I’m fond of CSS Modules along with SCSS instead of the slow CSS-in-JS solutions out there. Still, we need a way to manage multiple classes in className
property.
In order to mitigate this problem, I wrote a TypeScript function to deal with sequential or conditional class names situations:
/** * Generates the className attribute with the given class names. */ export function cn( ...items: ( string | null | undefined | (string | null | undefined)[] | Record<string, boolean> )[] ): string { let fin = ' '; for (const item of items) { if (typeof item === 'string') { fin += item + ' '; } else if (Array.isArray(item)) { for (const s of item) { if (typeof s === 'string') fin += s + ' '; } } else if (typeof item === 'object') { for (const key in item) { if (item[key]) fin += key + ' '; } } } return fin.substring(0, fin.length - 1); }
Example using some argument possibilities:
import {cn} from '@/funcs'; import c from './App.module.css'; function App() { return <> <div className={cn( c.first )} /> <div className={cn( c.first, c.second )} /> <div className={cn( [c.first, c.second], c.third )} /> <div className={cn( c.first, {[c.second]: true} )} /> </>; }
This covers all situations I ever faced, and it's basically the same syntax of classnames.
The spread operator version was added in February 9, 2023.
The multi-combination of parameters was added in December 30, 2024.