DEV Community

Sandrina Pereira
Sandrina Pereira

Posted on

CSS-in-JS - styled vs css prop

CSS-in-JS lovers, please help me understand why I should prefer using styled over CSS prop.

Not knowing immediately if it's a "real" React component or just an HTML element (and which one) is driving me nuts. 😰

// MyComponentStyles.js
const Styles = {
  item: css`
    color: tomato;
  `,
};

const Item = styled.div`
  color: tomato;
`;
Enter fullscreen mode Exit fullscreen mode
// MyComponent.js
return (
  <ul>
    {/* Approach #1 - I can easily tell what's the HTML tag
                      and spot any markup mistakes */}
    <div css={Styles.item}>Pizza</div>

    {/* Approach 2: - Can't tell if it's an actual component or
                      just a "css wrapper". */}
    <Item>Pizza</Item>
  </ul>
);
Enter fullscreen mode Exit fullscreen mode

Top comments (12)

Collapse
 
klaytonfaria profile image
Klayton Faria

Yo!
I like to use styled, since css prop depends on a bit more setup using babel or macro to reach the same result. For me, It really seems a decision-based in code readability and comprehension... Sometimes it's s driving me nuts also haha... But I rather keep it simple with less setup and additional imports and try to think in names to describe my component as a "css wrapper / styled element" than a component itself (E.g. ItemStyled).

// MyComponentStyles.js
export default {
    item: ({theme, color}) => css`
         color: ${color};
         background-color: ${theme.primary};
   `
}
// MyComponent.js
import AnotherComponent from './AnotherComponent';
import Styles from './MyComponentStyles';

const ItemStyled = styled.div(Styles.item);
const AnotherComponentStyled = styled(AnotherComponent)(Styles.item);

... 
<ItemStyled color="tomato">pizza</ItemStyled>
...
Collapse
 
luisvieira_gmr profile image
luis vieira • Edited

I usually prefer the css prop as you don’t need to be constantly creating and naming variables everytime you want to style an html element. Also last time i checked there seems to be better compatibility with accessibility tooling like axe

Collapse
 
geelen profile image
Glen Maddern

Hey Sandrina, so Styled Components was (I think??) the first to really popularize the const Item = styled.div approach, so this is partly my fault, sorry!!

One of the first feature requests for SC was a css style prop just like this which I argued against very strongly at the time, but I don't feel that strongly any more. At the time, that was partly to differentiate ourselves from Glamor (which we were building on top of), which had that feature, but also because SC was designed as a runtime-only library (no Babel transforms allowed, as a deliberate departure from CSS Modules which was tied to Webpack), and you can't really do a css prop without it. Plus, I only wanted one way of doing things, with the argument that if you preferred an alternative use Glamor, or later, Emotion.

But SC has the css prop now so now you can mix-and-match, so honestly, do whatever makes sense to you!

Personally, I really wanted to remove as much as possible from my "markup" section of a React component, so it was just structure and content, e.g.

return (
  <Wrapper>
    <Prompt>What is Delicious?</Prompt>
    <Answer>Pizza!</Answer>
  </Wrapper>
)
Enter fullscreen mode Exit fullscreen mode

This introduces a lot of local names (i.e. local to this file/directory) which I really like, but not everyone does. You're free to define them how & where you like, but I was really going for contextual names over mashing all the markup together.

The polar opposite (which is not what you're suggesting, but it's what I had in mind when I was writing SC), has so much "noise" that I wanted to avoid:

return (
  <div css={{
    display: 'flex',
    alignItems: 'center'
  }}>
    <h2 css={{
      ...typography.h2,
      ...borders.rounded.black
    }}>
       What is Delicious?
    </h2>
    <p css={{
      ...typography.p.grey90.lh14,
      paddingTop: '1rem'
    }}>
      Pizza!
    </p>
  </div>
)
Enter fullscreen mode Exit fullscreen mode

Honestly, your example using <div css={Styles.item}>Pizza</div> is almost as clean, makes the underlying HTML element explicit, and keeps the CSS and the "markup" (structure & content) separate, so I say it looks great, go for it!

Collapse
 
a_sandrina_p profile image
Sandrina Pereira

Thank you so much for this explanation and for being able to explain both sides of the same coin!

Definitely the "polar opposite" is the worse in my opinion. As you said - very noisy.

One last question: When it comes to generating CSS is there any "major" difference between both approaches?

Collapse
 
shavrin profile image
Kacper Olek

Separation of logic and styles is a good idea. You can name styled Item component as an ItemWrapper for better readability.

Collapse
 
a_sandrina_p profile image
Sandrina Pereira • Edited

Could you further explain the benefits of "separation of logic and styles". Where exactly styled is better than css prop in that matter?

Collapse
 
cullophid profile image
Andreas Møller

I think this is largely a leftover from the old days of web development. With react and other component based frameworks there isn't really any benefit to separating logic and styles

Collapse
 
merri profile image
Vesa Piittinen • Edited

React is at it's best with very interactive and dynamic interfaces, yet many use it to render mostly static sites where most of React's way to work as a single tree becomes a burden due to performance issues, and growing bundle sizes. Code splitting to multiple bundles is more of a workaround and a sign of an issue than a solution. User still needs to get all the data. JS execution is also expensive as a simple React app takes longer to complete first render than it takes to render a multimegabyte HTML without JS.

If you consider using more than one library/framework in a project and instead of building a monolith bundle you use a tool best fit for a specific task at hand then CSS-in-JS can be quite inflexible as sharing styles between multiple frameworks becomes an issue. You want to avoid unnecessary duplication.

If there are multiple projects that share a common style it makes much more sense to provide it in CSS than force a single CSS-in-JS solution on everyone, because JS libraries and tools come and go, but CSS stays. Devs love to have a go with new tools every now and then.

Then there is the fact for some parts of a site using vanilla JS can work very well. Not everyone likes this idea as there seem to be people who think everything has to go through a single solution and follow the one chosen thing. Even when it is ill-fitted to whatever is the task to be done.

So there is value in separation when aiming for a well performing site. The less runtime logic you have running the better.

Thread Thread
 
a_sandrina_p profile image
Sandrina Pereira

I'm afraid you misunderstood my question. I didn't ask if we should use "vanilla css" vs "css-in-js". I was talking only about CSS-in-JS approach, but within two techniques: Using a "css prop" or "styled module".

Regardless of that, thank you for your perspective. I pretty much agree with and you are saying :)

Thread Thread
 
cullophid profile image
Andreas Møller

I don't agree with that at all, react is excellent for static sites as well. Especially when using a framework like Gatsby or nextJS.
Frameworks has gotten a bad rep when it comes to performance, mostly because of performance and bloated bundles, but neither is because if the framework.

Collapse
 
cullophid profile image
Andreas Møller

I use both,
If I'm writing a component that is shared on different pages I will use styled.div....
Otherwise I just use

Collapse
 
atomxplus profile image
AtOmXpLuS

💘👻💘