loading...

CSS-in-JS - styled vs css prop

a_sandrina_p profile image Sandrina Pereira ・1 min read

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;
`;
// 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>
);

Discussion

markdown guide
 

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>
)

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>
)

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!

 

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?

 

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>
...
 

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

 

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

 

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

 

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

 

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.

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 :)

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.

 

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