Background
Have you ever seen a long list of class names with barely knowing which components we try to debug?
I cannot deny that Tailwind helps our web development faster, especially, with styling, but when we try to use many of its utility class names within a single element. As a result, we cannot see the actual identity of that component and it may become a guessing game.
One of the solutions is that we can add a unique id or class name to identify that component
but I’d admit as a developer that sometimes, I’m too lazy to put it, or copy/paste components somewhere but forget to change their class name identities.
Solution
To solve the above problem programmatically, I implemented a higher-order component (If you don’t know what it is, you can check this document out)
const withComponentClassName = (WrappedComponent) => { const WrapperComponent = (props) => { const componentName = WrappedComponent.displayName || WrappedComponent.name; const className = componentName ? `c-${componentName}` : ''; return ( <div className={className}> <WrappedComponent {...props} /> </div> ); }; return WrapperComponent;
}; export default withComponentClassName;
And then use it in components
export default withComponentClassName(MyComponent);
After that, it generates JSX like below
<div className="c-MyComponent"> <MyComponent {...props} />
</div>
Now every single component will have this pattern in DOM. We can clearly see where those elements are from.
The only trade-off with this approach is that we have an extra div
element wrapping our component that increases our DOM size, but in the long run, it has boosted my team’s development as well as UI debugging.
3 questions I stumped upon when I developed this approach:
- We still can forget to place it in our components, how to prevent that? – We implemented a custom ESLint rule to verify
export default
of our components withwithComponentClassName
usage (I’ll share it with more detail in another post) - Can we embed that class name into the component’s elements directly instead of adding an extra
div
? – The solution is more complicated and actually, it may make unexpected re-renderings due to class name prop/state updates, so we’ve accepted this simpler solution - Can we hide that class name addition layer on production? – Yes, we can add a condition in
withComponentClassName
like below
const withComponentClassName = (WrappedComponent) => { //production variable depends on your codebase setup if(production === true) { return WrappedComponent; } const WrapperComponent = (props) => {...}; return WrapperComponent;
}; export default withComponentClassName;