Emotion: Emotion Best Practices

Created on 5 Oct 2017  ยท  12Comments  ยท  Source: emotion-js/emotion

  • emotion version: 8+
  • react version: 15+

Problem description:

There have been a lot of helpful snippets and patterns in the slack channel and Github issues. I'd love to pull together a document of 'best practices' when using emotion.

In my case, I've been trying to use styled as much as possible, but I'm probably missing out on some benefits of extractStatic. In all honesty I'm just not sure. The original blog post was a great way to get people to step into css-in-js, and now I think there needs to a 'and here's how you do it' guide.

Suggested solution:

I can gather a document(s) of helpful issue solutions, but it would be invaluable to have a new doc file or homepage section with a brief guide to emotion for css users.

  • Most performant patterns
  • Most expressive patterns
  • Most common patterns
  • Best sibling libraries (polished, styled-system)

If the existing docs cover all these cases maybe it's just a matter of linking them up in one spot and writing some more description around them?

discussion

Most helpful comment

This is what I'm liking the most about emotion as a library. There are so many different ways to style our apps. I personally don't use BEM because I have no experience with it, but I'm digging what @richardanaya is doing for fans of that pattern. And this is one of a larger pattern where devs rely almost exclusively on css. I've also seen fans of object styles, those that use css or styled exclusively, and the hybrid patterns.

I think my personal answer to the best practice question is going to be some sort of hybrid solution that almost resembles BEM. Actually, I just glanced at the docs and no this does not resemble BEM all.

This is a rough outline

Globals
If you style your semantic tags well that can get you pretty far when mixed with css prop.
Make a reset, but make one that has a good basis of your design. This is a good start http://yegor256.github.io/tacit/. You should be able to run it through https://transform.now.sh/css-to-emotion/ and you'll have a nice little basis to build on after you customize it a bit. (I would actually just use injectGlobal on the string, but whatever works)

Primitives
These are things like

  • Box or View (Box is shorter)
  • Text
  • Button
  • Link

You use these as the structural elements on your page and all based on Box which is based on styled-system.

https://github.com/emotion-js/emotion/blob/gatsby/packages/site/src/components/Box.js

Blocks

http://getbem.com/introduction/

Standalone entity that is meaningful on its own.

Sounds about right.

I usually use styled , usually `styled(Box)``` for these larger components. They always seem to get more complicated than originally envisioned and get broken down into components (elements ๐Ÿ‘‡) in the normal wear and tear of development.

Elements

A part of a block that has no standalone meaning and is semantically tied to its block.

Damnit, ok it has some BEM characteristics.

When it comes to this situation I think to myself, "How many times am I going to style this element?" If it's more than once, I make a styled component. If I'm going to just style this element one time, most of the time I'm just using the css prop.

Modifiers

I'm not even going to get the quote...

This is actually pretty simple with css-in-js in general. If you are modifying some css property use whatever method available to change it. It's that simple.

Traits
๐Ÿ’ก This is where I've seen the lightbulb go off for many developers

Shoutout to @geelen who came up with this name.

Let's start with something simple.

const myCoolBg = 'linear-gradient( to bottom,#46C9E5 0%,#D26AC2 100% )';
const background = css`
  background: ${myCoolBg};
`

const PageContainer = styled('div')`
  ${background};
`

PageContainer and any other style block that has background will get the same cool background.

A/B expert Dan now says that we must support the reverse of the gradient. Lets make background a "live trait".

const pink = '#D26AC2';
const blue = '#46C9E5'
const background = (top, bottom) => css`
  background: linear-gradient( to bottom,${top} 0%,${bottom} 100% );
`

const PageContainer = styled('div')`
  ${background(pink, blue)};
`

It would be better to use props.

const background = (props) => css`
  background: linear-gradient( to bottom,${props.top} 0%,${props.bottom} 100% );
`

const PageContainer = styled('div')`
  ${background};
`

Any expression that is a function inside a styled style block will be called with props and context. This is pretty neat for nested calls.

const background = (props) => css`
  background: linear-gradient( to bottom,${props.top} 0%,${props.bottom} 100% );
`

const PageContainer = styled('div')`
  ${background};
`

// Somewhere else...

function getTopColor () {
     return 'pink'
}

function getBottomColor () {
     return 'blue'
}

const Home = () => {
     return <PageContainer top={getTopColor} bottom={getBottomColor} />
}

Its late. These are just some notes to get some ideas going.

PS Hotdog... ๐Ÿ˜‚

All 12 comments

This has been on my mind as well. My plan was to get version 8 out and then sit down and write about this.

We could use this issue to collect ideas and patterns ๐Ÿ‘

I offer my example in BEM ( http://getbem.com/introduction/ ) for css organization.I think it might be good for best practices suggestions since its pretty framework agnostic, component oriented, simple and somewhat popular:

https://codesandbox.io/s/wk2vo6zx87

import React from "react";
import { render } from "react-dom";
import { css } from "emotion";


const cssHotDog = css`
 &--hotdog-button, &--not-hotdog-button {
    border: solid 1px black;
    padding: 5px;
    margin-left: 5px
  }

  &--hotdog-button {
    background: red;
    color: white;    
  }

  &--not-hotdog-button {
    background: yellow;
    color: black;
  }
`;
const cssHotDog__hotdog_button = cssHotDog + "--hotdog-button";
const cssHotDog__not_hotdog_button = cssHotDog + "--not-hotdog-button";

const Hotdog = () => (
  <div className={cssHotDog}>
    ๐ŸŒญ
    <button className={cssHotDog__hotdog_button}>Hotdog</button>
    <button className={cssHotDog__not_hotdog_button}>Not Hotdog</button>
  </div>
);

render(<Hotdog />, document.getElementById("root"));;

This is what I'm liking the most about emotion as a library. There are so many different ways to style our apps. I personally don't use BEM because I have no experience with it, but I'm digging what @richardanaya is doing for fans of that pattern. And this is one of a larger pattern where devs rely almost exclusively on css. I've also seen fans of object styles, those that use css or styled exclusively, and the hybrid patterns.

I think my personal answer to the best practice question is going to be some sort of hybrid solution that almost resembles BEM. Actually, I just glanced at the docs and no this does not resemble BEM all.

This is a rough outline

Globals
If you style your semantic tags well that can get you pretty far when mixed with css prop.
Make a reset, but make one that has a good basis of your design. This is a good start http://yegor256.github.io/tacit/. You should be able to run it through https://transform.now.sh/css-to-emotion/ and you'll have a nice little basis to build on after you customize it a bit. (I would actually just use injectGlobal on the string, but whatever works)

Primitives
These are things like

  • Box or View (Box is shorter)
  • Text
  • Button
  • Link

You use these as the structural elements on your page and all based on Box which is based on styled-system.

https://github.com/emotion-js/emotion/blob/gatsby/packages/site/src/components/Box.js

Blocks

http://getbem.com/introduction/

Standalone entity that is meaningful on its own.

Sounds about right.

I usually use styled , usually `styled(Box)``` for these larger components. They always seem to get more complicated than originally envisioned and get broken down into components (elements ๐Ÿ‘‡) in the normal wear and tear of development.

Elements

A part of a block that has no standalone meaning and is semantically tied to its block.

Damnit, ok it has some BEM characteristics.

When it comes to this situation I think to myself, "How many times am I going to style this element?" If it's more than once, I make a styled component. If I'm going to just style this element one time, most of the time I'm just using the css prop.

Modifiers

I'm not even going to get the quote...

This is actually pretty simple with css-in-js in general. If you are modifying some css property use whatever method available to change it. It's that simple.

Traits
๐Ÿ’ก This is where I've seen the lightbulb go off for many developers

Shoutout to @geelen who came up with this name.

Let's start with something simple.

const myCoolBg = 'linear-gradient( to bottom,#46C9E5 0%,#D26AC2 100% )';
const background = css`
  background: ${myCoolBg};
`

const PageContainer = styled('div')`
  ${background};
`

PageContainer and any other style block that has background will get the same cool background.

A/B expert Dan now says that we must support the reverse of the gradient. Lets make background a "live trait".

const pink = '#D26AC2';
const blue = '#46C9E5'
const background = (top, bottom) => css`
  background: linear-gradient( to bottom,${top} 0%,${bottom} 100% );
`

const PageContainer = styled('div')`
  ${background(pink, blue)};
`

It would be better to use props.

const background = (props) => css`
  background: linear-gradient( to bottom,${props.top} 0%,${props.bottom} 100% );
`

const PageContainer = styled('div')`
  ${background};
`

Any expression that is a function inside a styled style block will be called with props and context. This is pretty neat for nested calls.

const background = (props) => css`
  background: linear-gradient( to bottom,${props.top} 0%,${props.bottom} 100% );
`

const PageContainer = styled('div')`
  ${background};
`

// Somewhere else...

function getTopColor () {
     return 'pink'
}

function getBottomColor () {
     return 'blue'
}

const Home = () => {
     return <PageContainer top={getTopColor} bottom={getBottomColor} />
}

Its late. These are just some notes to get some ideas going.

PS Hotdog... ๐Ÿ˜‚

@greggb I can

@richardanaya awesome example ๐Ÿ˜„ I personally never got into using BEM but I know it's tremendously popular so I imagine examples showing the best practices writing BEM styles with emotion will be super helpful for those who do utilize it.

This is one of the awesome things emotion! AFAIK doesn't force users to adhere to a specific naming convention or really anything like that, making it super easy for people like yourself, who utilize BEM, to migrate existing CSS codebases so that they can be rendered in a highly optimized manner - something that CSS has had a hard time achieving on it's own.

When I think of best practices in JS, I think of building software (or style layouts) using reusable bits of code which is one of the reasons why I love emotion. I imagine that most people probably utilizing emotion in their project from a within a shared folder (or theme.. something that contains code to be used in other places) however this may not be clear for everyone. I would love to discuss some ways in which everyone things application code should be structured. Some people are going to like keeping their styles close to their component and some are going to like centralizing them like I mentioned.

+-- src
| +-- Login
| +-- login.component.js
| +-- login.styles.js

+-- theme
| +-- index.js
| +-- static-styles.js
| +-- prop-based.js
+-- src
| +-- Login
| +-- login.component.js

I know this might seem minor but I think that specifying code reuse will be really beneficial. Additionally, showing people the correct way(s) to export styles is another minor detail but it can help save users from a lot of potential headaches, specifically if their not use to ES6.

That brings up another point - ES6. I think users should be encouraged to use ES6 and discouraged from using ES5. ES6 has been out for some time now and it's benefits are tremendous. Personally, I think that features like arrow functions, shorthand notation for object literals, etc.
make code more readable. At the same time ES6 really supercharges JS with a slew of new utilities like [first, ...rest], destructuring, and even template strings which emotion is built on! Using ES5 forfeits this functionality therefore I think that using it in any community examples should be discouraged.

@tgrecojs Nice!

I've been really enjoying colocating all my component files:
+-- src
| +-- components
| |+-- Login
| | +-- index.js (public)
| | +-- login.component.js (private)
| | +-- login.stories.js
| | +-- login.test.js
+-- theme
| +-- index.js
| +-- defaultTheme.js

Useful issues:

  • #287 Questions about Emotion patterns
  • #291 Best pattern for components of unknown type?

As someone who wrote BEM for 12-13 months non stop I can say it has its place in larger projects. @richardanaya idea makes me wonder if we could extract:

const cssHotDog__hotdog_button = cssHotDog + "--hotdog-button";
const cssHotDog__not_hotdog_button = cssHotDog + "--not-hotdog-button";

Automatically with a utility function of some sort :-? That piece of code is just boilerplate, and is usually more than 2 modifiers per block/component.

Here ya go @vladnicula https://codesandbox.io/s/j4jqqko9r5

From someone who has been using BEM in most of his projects, does it even make sense to use it in the context of styled components?

I think the two problems that BEM tried to solve were: 1) the specificity mess caused by global inheritance ("cascading") by essentially outlawing it, and 2) lack of re-usability by keeping things small and modular. Both of those things are solved by styled components right out of the box by having a local scope by default and the natural composability of components / functions.

I don't think we need it any more. Am I wrong?

@tstelzer not for styled react components. Not everyone uses emotion for react components. I use emotion to generate my css for web components

๐Ÿ‘ฉโ€๐ŸŽค

@richardanaya Do you have examples how you attached the styles into the shadowDom with emotion?

Was this page helpful?
0 / 5 - 0 ratings