Modern CSS-in-JS is the best thing that's happened to the web since components. Hands down. Let me explain. 👇
First we had the
style prop and that sucked. I hated CSS-in-JS and thought it was stupid. You can pry my CSS from my dead cold hands! shakes fist
Then came experiments.
Can we make the style prop easier to use? Can we still use class names to style with BEM like we used to? What about CSS files with fat semantic classes? Scoped styles maybe?
None of it quite worked. Everything was awkward in some way.
The style prop is great for individual components and breaks down when you want to change your general font size.
Class names give you all the power of CSS and BEM (tiny classes like .font1 .bold .bla). And it breaks down when you reuse components like building blocks. A component has the color defined and if you want to overwrite that you need something that understands classes and decides which one takes power and ugh don't get me started.
I may have once tried to make that work ...
Scoped CSS is better. That's what Vue uses. But it still sucks, if you ask me. You get a weird mix of global styles with local overwrites and mixing BEM and semantic classes and it gets messy fast. Leads to weird code too.
But then, then some beautiful soul came up with styled-components. I was in love.
The best way to make my argument is with an example. I recently implemented a colorful React stepper component for a client project.
Styled components and a couple libraries @Diegohaz built on top made it so easy it feels like cheating.
You have 9 steps. Each a different color once done. Blank with a grey outline otherwise.
Here's a CodeSandbox you can try.
Pretty isn't it? I think it is.
Here's all the component code 👇
Yep that's it. 12 lines of code.
<Stepper> component, the default export, takes the current
step and max number of steps,
maxSteps. It renders a
<Steps> component which deals with layouting. Inside goes an array of
<Step> gets an index, a flag saying whether it's
last, and whether it's been
done yet. Highlighted vs. unhighlighted state.
Steps render a
<Circle> component, pass-in the props, and inside goes either a number or a star emoji. Star is last.
Moving your visual UI logic out of your components and into styles is where CSS-in-JS shines. Focus your components on business logic, user experience, and hierarchy. Let your styles take care of your styling.
Just like our CSS Garden forebears envisioned. Remember CSS Gardens?
You might be too young. The world has moved on. CSS's initial promise is that we would completely decouple styling from document hierarchy and live a Zen stress free life.
Now look at us.
BUT ALL IS NOT LOST! Look at this beauty.
I'm using Diegohaz's reakit for base CSS stuff. He built a bunch of components on top of styled-components that have sane defaults and great composability.
No styles, just some basics.
Flex, for example, is a
display: flex. That's all.
<Steps> then is a flexbox div that centers its children and adds a
40px padding on top.
And then comes the
<Circle> component. The individual steps.
A few things are happening here. Let me explain.
- I'm using another of Diegohaz's libraries styled-tools. It's a suite of helper functions that make it easier to use component props from your CSS-in-JS styles
- I'm using a theme behind the scenes. A concept built into Reakit that lets you define global styles. Things like UI colors, font sizes, stuff like that.
- ALL of my visual logic is in this style
Let's break it down.
We start with a
Box, which is just a
Then we turn it into a circle with a border.
<code class="css"> border-radius: 100%;border: 1px solid;
Border and background color come from our
theme, based on the combination of
Here's how you read that:
- If prop
doneis true, get first argument, otherwise the second.
- With prop
- Get the
stepspalette from theme and take the
- Otherwise, get the
greypalette and take the
A similar process gives you the font color.
If step is
done, color is
white, otherwise the 2nd color from the
Then we have font size, bold fonts, widths and heights, and other normal CSS stuff to round off each step.
You can still use CSS nesting and meta classes just like you're used to.
&:last-child matches the last
<Step> and removes its margin so it doesn't mess with the layout.
- Components deal with business logic and UX
- Styles handle all visual logic
- Global theme handles generics
Yes that means you ca rebrand your whole app just by changing
Here's how it works 👇
And get thoughtful letters 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Ready to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz components your whole team can understand with React for Data Visualization
Curious about Serverless and the modern backend? Check out Serverless Handbook, modern backend for the frontend engineer.
Ready to learn how it all fits together and build a modern webapp from scratch? Learn how to launch a webapp and make your first 💰 on the side with ServerlessReact.Dev
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️