Create a flexible utility function classNames designed to combine various types of inputs into a single string of CSS classes. This function should be able to process:
- Individual strings: Added directly to the final class list.
- Arrays of class names: Each item within the array must be tested.
- Objects where keys are class names and values are boolean: Keys are treated as class names, and their boolean values determine whether they are included in the output (true) or excluded (false).
🔗Classnames 🟡 Medium🧩 Pattern – JavaScript Essentials
Examples
classNames('header', 'active'); // 'header active'
classNames('item', { selected: true }); // 'item selected'
classNames({ 'is-hidden': true }); // 'is-hidden'
classNames({ 'is-visible': false }); // ''
classNames({ menu: true }, { open: true }); // 'menu open'
classNames({ primary: true, disabled: true }); // 'primary disabled'
classNames({ success: true, warning: false, error: true }); // 'success error'
classNames(['btn', { 'btn-primary': true }]); // 'btn btn-primary'
classNames('icon', null, undefined, 0, { large: true }); // 'icon large'
classNames({ 'text-red': true, 'font-bold': true }, 'p-4'); // 'text-red font-bold p-4'Code language: JavaScript (javascript)classNames function
/**
* @param {...(any|Object|Array<any|Object|Array>)} args
* @return {string}
*/
export default function classNames(...args) {
let classes = [];
for (let arg of args) {
if (!arg) {
continue; // Ignore - null, undefined, false,'';
}
const type = typeof arg;
if (type === "string" || type === "number") {
classes.push(String(arg));
} else if (Array.isArray(arg)) {
const result = classNames(...arg);
if (result) {
classes.push(result);
}
} else if (type === "object") {
for (const key in arg) {
if (arg[key]) {
classes.push(key);
}
}
}
}
return classes.join(" ");
}Code language: JavaScript (javascript)