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 cls(...names: (string | undefined)[]): string; export function cls(names: (string | undefined)[]): string; export function cls(names: Record<string, boolean>): string; export function cls(names: any): string { if (typeof names === 'string' && arguments.length === 1) { // just 1 string return names === undefined ? '' : names; } else if (typeof names === 'string' && arguments.length > 1) { // multiple strings let s = ''; for (const name of arguments) { if (name !== undefined) s += name + ' '; } return s; } else if (Array.isArray(names)) { // string array let s = ''; for (const name of names) { if (name !== undefined) s += name + ' '; } return s; } else if (typeof names === 'object') { let s = ''; for (const name in names) { if (names[name]) s += name + ' '; } return s } else { throw 'Invalid class name input!'; } }
Example using the 4 argument possibilities:
import {cls} from '@/funcs'; import c from './App.module.scss'; function App() { return <> <div className={cls( c.first )} /> <div className={cls( c.first, c.second )} /> <div className={cls( [c.first, c.second] )} /> <div className={cls({ [c.first]: true, [c.second]: false, })} /> </>; }
This covers all situations I ever faced.
The spread operator version was added in February 9, 2023.