TailwindCSS is powerful, but it can be hard to read. Writing conditional styles can also be a hassle. So I decided to create a lightweight and simple library to solve this problem.
TailwindBox
vectordxy / tailwindbox
Easily manage TailwindCSS styles with simple object-like structures
π§ Installation
Install TailwindBox via npm or yarn:
npm install tailwindbox
# or
yarn add tailwindbox
π Usage
Here's a quick example of how to use TailwindBox:
import { tw } from "tailwindbox";
function App() {
const isDarkMode = true;
const styles = tw({
base: "p-4 rounded-lg shadow-md",
dark: { if: isDarkMode, classes: "bg-gray-800 text-white" },
light: { if: !isDarkMode, classes: "bg-white text-black" },
});
return <div className={styles}>Hello, TailwindBox!</div>;
}
export default App;
-
base
: Always applies the base styles (p-4 rounded-lg shadow-md
). -
dark
: Appliesbg-gray-800 text-white
only ifisDarkMode
is true. -
light
: Appliesbg-white text-black
only ifisDarkMode
is false.
π Features
- Object-Like Structure: Define TailwindCSS styles in an object-based format.
- β¦
TailwindBox makes your TailwindCSS code cleaner and easier to manage. Here's a quick example of how to use TailwindBox:
import { useState } from "react";
import { tw } from "tailwindbox";
function App() {
const [isOpened, setIsOpened] = useState(false);
const styles = tw({
base: "pt-2 text-center font-light",
open: { if: isOpened, classes: "inline-block border-t p-7" },
closed: { if: !isOpened, classes: "hidden" },
});
return (
<div>
<button
onClick={() => setIsOpened((prev) => !prev)}>
Toggle Content
</button>
<div className={styles}>Hello World!</div>
</div>
);
}
export default App;
-
base: Always applies the base styles (
pt-2 text-center font-light
). -
open: Applies
inline-block border-t p-7
only ifisOpened
istrue
. -
closed: Applies
hidden
only ifisOpened
isfalse
.
Features
- Object-Like Structure: Define TailwindCSS styles in an object-based format.
- Conditional Classes: Apply classes dynamically based on your application's state.
- Improved Readability: Simplify long and complex class strings.
- Lightweight: A minimal library designed for TailwindCSS users.
It will be a great help when you develop with TailwindCSS. Try it out, and feel free to share your feedback anytime!
Top comments (16)
That reminds me a lot of cx from @emotion/css, which boils down to:
Any particular reason you decided to have an object structure instead?
Thank you for the question. Actually, my library was influenced by
emotion
, as I thought its structure was well-designed. The main reason I created this library was to improve projects that were already built with TailwindCSS. I noticed that conditionalclassName
strings often became too long and complicated, and I wanted a way to simplify that.If youβre starting a project, using
emotion
or another styling solution might be a better choice. However, for projects already written with TailwindCSS, I believe this library makesclassName
simpler.I chose the object structure simply because it felt familiar to me. I found the object-based approach clear. This approach started from my own perspective, but Iβm constantly learning through feedback! I appreciate your valuable thoughts.
Thank you for your response! Itβs possible to use emotion/cx with tailwind (string css classes defined elsewhere) as well, but youβre right itβs much easier to use something else of tailwind. Would you say your library can be used as a bridge while refactoring as well or is the purpose to simplify use of tailwind and promote it?
This library was primarily designed as a refactoring tool. Itβs not intended to promote the use of TailwindCSS but rather to simplify className in projects that already use TailwindCSS. I truly appreciate your interest. Thank you!
@moopet regarding
In this case, I recommend writing out the class names:
isWide ? mx-5 : mx-3
.Not just for tailwind, but for anything in programming, otherwise you'll have a hard time finding them later as the code base grows (grep test).
I agree, but it's an example of how Tailwind (and lots of other modern things with build steps) does magic in the background, where if you don't know about it, you're going to fall into traps.
The example you give (switching between dark and light themes) is exactly why tailwind is a bad solution for styling things in the first place.
But I thought they had prefixes for that sort of thing, like
dark:text-black
or similar? I mean, obviously they'd only support two options whereas your solution could cope with many - or straight CSS could cope with unlimited options.Thank you for your feedback! I created this library to solve issues in React. When conditional logic is applied,
className
often become difficult to read. For example, something likeclassName='${isOpened ? "inline-block" : "hidden"} text-center font-light border-t p-7 m-5 text-sm'}
is too long. The main goal is to make it easier to manage styles based on variables in React components. The dark mode example wasnβt the best choice to explain this. Iβll update the example to better reflect the libraryβs purpose.As a junior React developer, I donβt have much experience with plain CSS, so I didnβt consider using it. Your feedback has helped me understand how to approach CSS better. I truly appreciate your insights. Thank you!
Tailwind is the source of a lot of those problems as far as I'm concerned.
If you use conditional logic like that, it can... not always work.
Tailwind does something crazy, it basically searches the js files for things that look like its known class names and then only includes those in the build. That means if you have something like
mx-${isWide ? 5 : 3}
neithermx-3
normx-5
will be included, but if your page is discussing the merits of the Mazda mx-5, then you're in luck and it will work... half the time.My issue is that people are having to make hacks upon hacks just to get back to the point where CSS already solved things :/
Probably they do, not only with CSS.
The whole mess with CSS started because an attempt to find some good system to organize styles, we've got css-in-js, it was better because code and styles were kept together and no need to jump between files, tailwind goes in the same direction, it's easier when styles closer to hmtl markup.
Tailwind CSS was actually created to solve problems with consistency, which it does quite well.
Here's an interesting article which discusses that (a bit):
adamwathan.me/css-utility-classes-...
Consistency is another side of the same issue.
Article is good, I read it some time ago.
Personally I like plain css, now when nesting natively supported, or css modules. Tailwind nice for layout related things, for don't repeat flex with centering all over again, and few more.
But it brings some old problems back, since it's gathering classes from source code, it works differently on dev mode and after bundling, in result works in dev, but messed up after bundling it.
In my experience with Tailwind, it hasn't ever applied CSS differently in development than in a build. If it did, it probably worked in a build but not in development.
For me, it's awesome; it helps with reusability and consistency, responsiveness, accessibility, and a lot more.
It's a lot easier to write
Than the same HTML with
Or course there are times when I just use the style prop instead, but tailwind is generally a lot faster.
But I think CSS-in-JS is the wrong direction, as well :P
Interesting idea, I will give it a try later.
Curious, what will happen with this styles object during minification?
With tailwind can also use classic classNames like this
Thank you for the question!
To be honest, I havenβt thought much about how minification would affect this. I assume it depends on the build tool being used (e.g., Vite, Webpack). However, JavaScript object keys are typically not changed during minification, so the
styles
object is likely to remain unchanged. Iβll make sure to look into this further!@apply
is also a great solution. However, this library was specifically designed to make conditional styling simpler. In particular, it can be helpful in situations where styles need to be applied dynamically based onvariables
.Thank you again for your valuable feedback. It gives me a great opportunity to learn and grow!