JSPM

  • Created
  • Published
  • Downloads 774252
  • Score
    100M100P100Q168317F
  • License MIT

high performance css-in-js

Package Exports

  • emotion
  • emotion/babel
  • emotion/lib/index
  • emotion/lib/sheet
  • emotion/react
  • emotion/server

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (emotion) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

emotion
emotion

high performance js for your css

npm version Build Status codecov gzip size size

Install

npm install -S emotion

.babelrc

{
  "plugins": [
    "emotion/babel"
  ]
}

Extract Mode

The default settings enable css extraction.

This js file, h1.js

import styled from 'emotion/react'

const H1 = styled('h1')`
  color: #ffd43b;
`

During babel compilation emotion will create h1.emotion.css and add import './h1.emotion.css' to the top of h1.js

.css-H1-duiy4a {
  color: blue
}

h1.js after babel compilation

import './h1.emotion.css'
import styled from 'emotion/react'

const H1 = styled('h1', 'css-H1-duiy4a')

Browser Support no ie11 support (css vars)

Inline Mode

  • Only extracts styles without dynamic values. (we're working on this)
  • No css var requirement
  • Same speed as default mode in benchmarks
  • Works with SSR

Extracted:

const H1 = styled('h1')`
  color: #ffd43b;
`

Not extracted

const H1 = styled('h1')`
  color: ${props => props.color};
`

Configure babel

.babelrc

{
  "plugins": [
    ["emotion/babel", { "inline": true }]
  ]
}

This js file, h1.js

import styled from 'emotion/react'

const H1 = styled('h1')`
  color: ${props => props.color};
`

h1.js after babel compilation

import './h1.emotion.css'
import styled from 'emotion/react'

const H1 = styled('h1', 'css-H1-duiy4a', [props => props.color], function createEmotionStyles(x0) {
  return [`.css-H1-duiy4a { color:${x0} }`]
})

Browser Support anything React supports

API

styled

import styled from 'emotion/react'

const H1 = styled('h1')`
  color: blue;
  font-size: 48px;
  transform: scale(${props => props.scale});
`

function Greeting ({ name }) {
  return <H1 scale={2}>Hello {name}</H1> // blue, 48px, and scaled 2x text
}


// You can also pass components in

const H2 = styled(H1)`
  font-size: ${fontSize * 2/3}px;
  color: red;
`

function Greeting ({ name }) {
  return <H2>Hello {name}</H2> // red, 32px, and scaled 2x text
}

// this works too

const H3 = styled.h3`
  font-size: ${fontSize * 1/3}px;
  color: red;
`

function Greeting ({ name }) {
  return <H3>Hello {name}</H3> // red, 16px text
}

// You can also pass refs down using innerRef
const H1 = styled('h1')`
  color: red;
`

function Greeting ({ name }) {
  // will turn into to <h1 className="generated-className" ref={() => console.log('hello!')}>Hello {name}</h1>
  return <H1 innerRef={() => console.log('hello!')}>Hello {name}</H1> 
}

css

css takes in styles and returns a class name. It is the foundation of emotion.

const flex = css`
  display: flex;
`
const justifyCenter = css`
  composes: ${flex};
  justifyContent: center;
`

<div className={justifyCenter}>
 Centered Content
</div>

Objects as Styles

css can also take an object as a parameter. This allows you to use your existing object styles in the emotion ecosystem. Another great benefit is that you can now use polished with emotion!

import { css } from 'emotion'
importimport { lighten, modularScale } from 'polished'

const cssA = {
  color: lighten(0.2, '#000'),
  "font-size": modularScale(1),
  [hiDPI(1.5)]: {
    "font-size": modularScale(1.25)
  }
}

const cssB = css`
  composes: ${cssA}
  height: 64px;
`

const H1 = styled('h1')`
  composes: ${cssB}
  font-size: ${modularScale(4)};
`

const H2 = styled(H1)`font-size:32px;`

<H2 scale={2} className={'legacy__class'}>
  hello world
</H2>

css prop

// To use the css prop you have to import css just like importing React for jsx
import { css } from 'emotion'


function SomeComponent (props) {
  // Create styles as if you're calling css and the class will be applied to the component
  return (<div css={`
    color: blue;
    font-size: ${props.fontSize}px;

    &:hover {
      color: green;
    }

    & .some-class {
      font-size: 20px;
    }
  `}>
    This will be blue until hovered.
    <div className="some-class">
      This font size will be 20px
    </div>
  </div>)
}

composes property

The composes property is based on css modules' composes property.

import { fragment, css } from 'emotion'
import styled from 'emotion/react'

// Define a class
const flexCenter = css`
  display: flex;
  justify-content: center;
  align-items: center;
`

// You can use compose them with the composes property
const flexCenterClass = css`
  composes: ${flexCenter};
  flex-direction: column;
`

// You can also use them in styled.* and the css prop
const FlexCenterComponent = styled.div`
  composes: ${flexCenter};
`


const flexWrap = css`
  flex-wrap: wrap;
`

// You can compose with use multiple classes
const ColumnCenteredComponent = styled.div`
  composes: ${flexCenter} ${flexWrap};
`

// You can also use composes with regular classes or classes from a css module
const CssModuleComponent = styled.h1`
  composes: ${'some-class'} ${styles.header};
`

// composes MUST be the first rule, e.g. this doesn't work
const cls = css`
  font-size: 20px;
  composes: ${flexCenter}
`

// composes also does not work in nested selectors, e.g. this doesn't work
const cls = css`
  & .flex {
      composes: ${flexCenter}
  }
`

keyframes

import { keyframes } from 'emotion'
import styled from 'emotion'

// This returns a animation
const bounce = keyframes`
  from {
    transform: scale(1.01);
  }
  to {
    transform: scale(0.99);
  }
`

// You can use them in styled components or anything else
const AnimatedDiv = styled.div`
  animation: ${bounce} 0.2s infinite ease-in-out alternate;
`

fontFace

import { fontFace } from 'emotion'

fontFace`
  font-family: 'Patrick Hand SC';
  font-style: normal;
  font-weight: 400;
  src: local('Patrick Hand SC'), local('PatrickHandSC-Regular'), url(https://fonts.gstatic.com/s/patrickhandsc/v4/OYFWCgfCR-7uHIovjUZXsZ71Uis0Qeb9Gqo8IZV7ckE.woff2) format('woff2');
  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
`

Server-Side Rendering

Server-Side Rendering in emotion currently only works in inline mode. It's similar to glamor's api. For an example of emotion and next.js checkout the with-emotion example in the next.js repo.

extractCritical

This returns an object with the properties html, ids and css. It removes unused rules that were created with emotion(it still includes rules that were inserted with injectGlobal).

import { renderToString } from 'react-dom/server'
import { extractCritical } from 'emotion/server'
import App from './App'


const { html, ids, css } = extractCritical(renderToString(<App/>))

hydrate

hydrate should be called on the client with the ids that extractCritical returns. If you don't call it then emotion will reinsert all the rules.

import { hydrate } from 'emotion'

hydrate(ids)

vue styled

<template>
  <div id="app">
    <styled-div>This should have a blue background.</styled-div>
    <styled-component></styled-component>
  </div>
</template>

<script>
import BoringComponent from './components/BoringComponent'
// Import styled from emotion/vue instead of emotion/react
import styled from 'emotion/vue'

// You can use styled.* just like with React
const StyledDiv = styled.div`
  background: blue;
`

// You can also pass components in
const StyledComponent = styled(BoringComponent)`
  display: flex;
  justify-content: center;
`

export default {
  name: 'app',
  components: {
    'styled-div': StyledDiv,
    'styled-component': StyledComponent
  }
}
</script>

Usage with CSS Modules

emotion works well with CSS Modules but it requires a bit of configuration.

  1. In your webpack config add the exclude option with this regex /emotion\.css$/ to your loader for css so that emotion's static css isn't imported as a CSS Module.
  2. Add another object to your modules.use with your css loaders but with CSS Modules disabled and set the test field to the same regex as above /emotion\.css$/.

attr

The attr CSS function is supported in a basic capacity.

/* get value from `width` prop */
width: attr(width vw);

/* specify type or unit to apply to value */
width: attr(width vw);

/* fallback value if props.width is falsey */
width: attr(width vw, 50);
const H1 = styled.h1`
  font-size: attr(fontSize px);
  margin: attr(margin rem, 4);
  font-family: sans-serif;
  color: attr(color, ${colors.pink[5]});
  @media (min-width: 680px) {
    color: attr(desktopColor);
  }
`

const Title = ({ title, scale }) => {
  return (
    <H1 fontSize={16 * scale} desktopColor={colors.gray[5]}>
      {title}
    </H1>
  )
}