About this post
In this post, we'll create a custom function for handling conditional classNames
in your projects! It'll be minimal and let you forget about installing additional packages in most cases, as you can tailor it to your project needs.
Table of Contents
About code pool
I decided to create a reusable collection of bare UI components and generic functions that I believe can be more useful—if not better—than a standard starter kit. While a starter kit may fit all your needs in every aspect, this is often rare. In most cases, you will encounter many unnecessary modules, and over time, you might find the structure too rigid to implement your desired changes and patterns.
With the SOC (Separation of Concerns) convention in mind, we will enhance our assets and confidently create a starter for our project in no time by selecting only the usable components and utilities!
I definitely believe that re-inventing the wheel isn't wise, but relying solely on an all-in-one solution can limit your ability to identify and solve problems. I think it's important to strike a balance between using ready-to-use assets and creating your own solutions, as this approach can help you improve your skills over time. Consider each module in the "code pool" series as a wheel that is functional and open to improvements and customizations!
Why to use?
Here are the main reasons to use this instead of clsx, classnames, and other similar npm packages:
- It reduces at least one dependency!
- It's customizable, allowing for interception or modifications if needed!
CX Utility
This function is a single module that handles all your multi-className concerns!
type ClassValue = string | boolean | null | undefined; type ClassArgument = ClassValue | ClassValue[] | Record<string, any>;
export const cx = (...classes: ClassArgument[]): string => { const processedClasses: string[] = []; for (let i = 0; i < classes.length; i++) { const item = classes[i]; if (!item) continue; if (typeof item === 'string' && item !== '') { processedClasses.push(item); } else if (Array.isArray(item)) { for (let j = 0; j < item.length; j++) { const nestedResult = cx(item[j]); if (nestedResult) { processedClasses.push(nestedResult); } } } else if (typeof item === 'object') { const keys = Object.keys(item); for (let k = 0; k < keys.length; k++) { const key = keys[k]; if (item[key]) { processedClasses.push(key); } } } } return processedClasses.join(' '); };
This will accept classes just as clsx
or classnames
do and return a single string at the end!
And here is a usage example:
... <div className={cx( 'bg-slate-50', 'rounded-3xl', 'overflow-hidden', 'border-2 border-black-body', 'my-2' )} /> ...