Opentrons: RFC: Introduce styled-components to monorepo

Created on 27 Jan 2020  Â·  4Comments  Â·  Source: Opentrons/opentrons

The What:

Styled-components is a CSS-in-JS styling library that uses tagged template literals in JavaScript to provide a platform that allows you to write CSS to style react components.

Styled-components is the result of wondering how we could enhance CSS for styling React component systems. By focusing on a single use case we managed to optimize the experience for developers as well as the output for end users.

The Why:

I copied and pasted this from https://styled-components.com/docs/basics#motivation.

  • Automatic critical CSS: styled-components keeps track of which components are rendered on a page and injects their styles and nothing else, fully automatically. Combined with code splitting, this means your users load the least amount of code necessary.
  • No class name bugs: styled-components generates unique class names for your styles. You never have to worry about duplication, overlap or misspellings.
  • Easier deletion of CSS: it can be hard to know whether a class name is used somewhere in your codebase. styled-components makes it obvious, as every bit of styling is tied to a specific component. If the component is unused (which tooling can detect) and gets deleted, all its styles get deleted with it.
  • Simple dynamic styling: adapting the styling of a component based on its props or a global theme is simple and intuitive without having to manually manage dozens of classes.
  • Painless maintenance: you never have to hunt across different files to find the styling affecting your component, so maintenance is a piece of cake no matter how big your codebase is.
  • Automatic vendor prefixing: write your CSS to the current standard and let styled-components handle the rest.
  • You get all of these benefits while still writing the CSS you know and love, just bound to individual components.

The How:

All of these examples and more exist at https://styled-components.com/docs/basics.

Basic Component:
This example creates two simple components, a wrapper and a title, with some styles attached to it.

// Create a Title component that'll render an <h1> tag with some styles
const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
`;
// Create a Wrapper component that'll render a <section> tag with some styles
const Wrapper = styled.section`
  padding: 4em;
  background: papayawhip;
`;
// Use Title and Wrapper like any other React component – except they're styled!
render(
  <Wrapper>
    <Title>
      Hello World!
    </Title>
  </Wrapper>
);

Adapting based on props:
You can pass a function ("interpolations") to a styled component's template literal to adapt it based on its props.

This button component has a primary state that changes its color. When setting the primary prop to true, we are swapping out its background and text color.

const Button = styled.button`
  /* Adapt the colors based on primary prop */
  background: ${props => props.primary ? "palevioletred" : "white"};
  color: ${props => props.primary ? "white" : "palevioletred"};
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
`;
render(
  <div>
    <Button>Normal</Button>
    <Button primary>Primary</Button>
  </div>
);

Additional Advantages

  • The toolchain is pretty simple, it's basically a matter of adding the library to our package.json and importing
  • The babel-plugin-styled-components adds additional support and is a nice to have. This also would be easy to add to our existing codebase.
  • Styled-components can be used with existing css if we really needed to
  • Since it's in JS we can test styled-components with Jest (there is a testing utility library):
    expect(button).toHaveStyleRule('color', 'blue');
  • Has support for TypeScript

Considerations

  • A new technology to learn (cognitive overhead)
  • May force some refactors and additional considerations around component architecture (i don't think this is a bad thing but it is extra work)
  • Two ways for styling components temporarily until we phase out the old styles
  • Additional dependency in our codebase
JS Tech Debt RFC

Most helpful comment

I'd like to open up the discussion about why css modules aren't cutting it for us as an org. What are our current pain points, and do we have a plan to use the tools that styled components offer to address those pain points?

Super good question. Here's a dump of pain-points that I've encountered and observed in no particular order:

  • CSS Modules are only scoped if you use classname selectors, and we've introduced inadvertent bugs across projects with implicitly global non-classname selectors
  • Specificity wars are still a thing

    • Scarily, depending on certain build config, I've seen the winners of certain specificity battles change between prod and dev

    • More specifically, this happened when I tried to set "sideEffects": false in CL's package.json to reduce application bundle sizes

  • Sharing styles is difficult, both between components and between JS and CSS

    • We currently rely on a combination of global CSS variables and

    • CSS property sets, which were a proposed CSS feature that got rejected

    • We have (and have had) instances where color hex values need to be shared between CSS and JS and we don't have a good way of doing this

  • We end up with dead CSS, which increases maintenance costs
  • CSS modules make it a little to easy to blur the lines between presentational and container components, because adding a div with a className somewhere is too easy

    • Obviously, styled-components by itself won't fix this, but I think it adds friction to that particular flow, helping us to fall into more disciplined patterns

  • Server-side rendering is prohibitively difficult

    • This is more webpack's fault than CSS Modules, but style-loader is bad at SSR

All 4 comments

Read through the styled-components doc and I'm in favor of gradually introducing styled-components.

Does anyone have any ideas for new or existing components where we could start to try this out?

@mcous awesome! I think the shared components _could_ potentially be a good candidate(s) for this. Stuff like: buttons, alerts, etc. My rationale here is that components are fairly isolated and organized. This also provides the opportunity for folks from different teams to start interacting with styled-components but not have a lot of conflicts with other work streams. Thoughts?

So here's my take from the perspective of someone who's never used styled components before — this seems very cool and powerful. I love that styled components are able to leverage the full power of JS. I see a lot of potential for being able to clearly define (AND test) smart styling logic using patterns like prop receivers.

The selfish side of me wants to go ahead and adopt this ASAP because this seems like a great thing to learn, but before I can responsibly do that I guess I'd like to open up the discussion about why css modules aren't cutting it for us as an org. What are our current pain points, and do we have a plan to use the tools that styled components offer to address those pain points?

As addressed in this RFC, adopting a new tool always comes at a cost. It's another thing for everyone to have to buy into, and it introduces further cognitive overhead in terms of patterns and practices that the entire frontend team should understand. I don't think this is a bad thing, I just think it's important for all of us to have a solid idea of why we would be adopting this in the context if our org, and how we as an org plan to responsibly use this tool.

I haven't had to fight with CSS too much since I've been here, so I'd like to hear from the rest of @Opentrons/js. At the current moment I agree with @mcous — I'm in favor of gradually introducing styled-components.

@iansolano thanks for taking initiative on this and getting this discussion going! I can def see this creating some solid infrastructure around more flexible/reliable/understandable styling.

As an aside, I love this:

Since it's in JS we can test styled-components with Jest (there is a testing utility library):
expect(button).toHaveStyleRule('color', 'blue');

I'd like to open up the discussion about why css modules aren't cutting it for us as an org. What are our current pain points, and do we have a plan to use the tools that styled components offer to address those pain points?

Super good question. Here's a dump of pain-points that I've encountered and observed in no particular order:

  • CSS Modules are only scoped if you use classname selectors, and we've introduced inadvertent bugs across projects with implicitly global non-classname selectors
  • Specificity wars are still a thing

    • Scarily, depending on certain build config, I've seen the winners of certain specificity battles change between prod and dev

    • More specifically, this happened when I tried to set "sideEffects": false in CL's package.json to reduce application bundle sizes

  • Sharing styles is difficult, both between components and between JS and CSS

    • We currently rely on a combination of global CSS variables and

    • CSS property sets, which were a proposed CSS feature that got rejected

    • We have (and have had) instances where color hex values need to be shared between CSS and JS and we don't have a good way of doing this

  • We end up with dead CSS, which increases maintenance costs
  • CSS modules make it a little to easy to blur the lines between presentational and container components, because adding a div with a className somewhere is too easy

    • Obviously, styled-components by itself won't fix this, but I think it adds friction to that particular flow, helping us to fall into more disciplined patterns

  • Server-side rendering is prohibitively difficult

    • This is more webpack's fault than CSS Modules, but style-loader is bad at SSR

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aciceri picture aciceri  Â·  6Comments

lmtgalhardo picture lmtgalhardo  Â·  9Comments

JohnGoertz picture JohnGoertz  Â·  6Comments

nickcrider picture nickcrider  Â·  3Comments

MarcelRobitaille picture MarcelRobitaille  Â·  7Comments