38
🧶 Implicit CLSX in React
Using clsx
or classnames
in React lately has become a trend with utility-first CSS frameworks like Tailwind CSS, where you have to write a lot of classes, and sometimes also with conditionals.
If you come from a framework like Vue you may saw that there you have this Class Binding functionality out of the box.
In this blog post I will show you how you can patch React library, so you don't have import clsx
everywhere where you need it, and to have this functionally out of the box also in React.
☢️ This is just for learning purposes. Use at your own risk
yarn create react-app implicit-clsx
cd implicit-clsx
yarn add clsx
yarn remove react
Install react
under raw-react
name (More about NPM Aliases)
yarn add raw-react@npm:react
my-react/index.js
module.exports = require('raw-react')
my-react/jsx-runtime.js (About JSX Runtime)
module.exports = require('raw-react/jsx-runtime')
my-react/jsx-dev-runtime.js (About JSX Runtime)
module.exports = require('raw-react/jsx-dev-runtime')
Install my-react
as react
package (More about NPM Aliases)
yarn add react@file:my-react
Now let's patch JSX Runtime to check for className
. Here comes the hard work 😀
my-react/jsx-dev-runtime.js
module.exports = require('raw-react/jsx-dev-runtime')
const clsx = require('clsx').default
const jsxDEV = module.exports.jsxDEV
module.exports.jsxDEV = function() {
if (typeof arguments[0] === 'string' && arguments[1].className) {
arguments[1].className = clsx(arguments[1].className)
}
return jsxDEV.apply(undefined, arguments)
}
Now it's time to explain what gibberish I wrote here 🤣 I will explain some things only everything else I think it's clear
Signature of function jsxDEV
is type, props, key
. So arguments[0]
is type
and arguments[1]
is props
And we check if type is a string, because in react-dom
host elements can be only strings, we don't want to change for example className
on some function or class components.
And second we check if we have className
prop, we patch it with a clsx
call.
Last line in the function we just forward everything to the native jsxDEV
To have this work also on build, you will need to apply this patch also to
jsx
andjsxs
inmy-react/jsx-runtime.js
see repo link at the end
yarn add react@file:my-react
Replace line with a single className
as string
<div className="App">
To something that usually can be passed to clsx
<div className={["App1", "App1", { "App2": true }]}>
yarn start
Working example https://github.com/iamandrewluca/implicit-clsx
I played around with TypeScript version, but couldn't make it work because of types mismatch, needs more investigation.
And we are done! Thanks for reading my blog posts!
Cover Photo by Ash from Modern Afflatus on Unsplash
38