- emotion.sh/docs/introduction
- github.com/emotion-js/emotion
- 9.1k stars
- 216 open issues
- 80kb bundle size
- Comparison with styled-components
- Companies that use emotion
Using the css
prop and POJOs
/** @jsx jsx */
import { jsx } from '@emotion/core'
const SomeComponent = () => (
<div
css={{
color: 'hotpink'
}}
/>
)
Also can write inline css via the css
import
/** @jsx jsx */
import { css, jsx } from '@emotion/core'
const base = css`
color: hotpink;
`
const SomeComponent = () => (
<div
css={css`
${base};
background-color: #eee;
`}
/>
)
Note: there is a babel plugin babel-plugin-emotion to do the pragma/jsx
stuff
Using styled-components
-esque api
import styled from '@emotion/styled'
const Button = styled.button`
color: turquoise;
`
- styled-system.com
- github.com/styled-system/styled-system
- 4.9k stars
- 18 open issues
- 18kb bundle size
- Mark Dalgleish twitter endorsement
- @types/styled-system
- Figma integration!
You can easily add common props to components with nice (and responsive) shorthand methods
import styled from '@emotion/styled'
import { space, color, layout } from 'styled-system'
const Box = styled.div({
space,
color,
layout
})
<Box
// Arrays as values to set styles responsively using a mobile-first approach
width={[
1, // 100% below the smallest breakpoint (all viewports)
1 / 2, // 50% from the next breakpoint and up
1 / 4, // 25% from the next breakpoint and up
]}
// These values are from a standard spacing scale, default to powers of 2
// - p={1} -> padding={1} -> padding="2px"
// - mb={2} -> marginBottom={2} -> marginBottom="4px"
p={1}
mb={2}
// Sets the background-color to whatever value passed to bg here
bg="purple"
>
This is a tomato box, with responsive width, some padding, and margin bottom
</Box>
Can also be used as inline css, pulling values from the theme
object (see: next section)
const Box = () => (
<div
css={css({
width: [
1,
1 / 2,
1 / 4,
],
p: 1,
mb: 2,
bg: 'purple',
})}
>
This is a tomato box, with responsive width, some padding, and margin bottom
</div>
)
Setting up theme variables are defined as such
const theme = {
colors: {
primary: '#000e1a',
secondary: '#fff',
purple: '#007ce0',
magenta: '#004175',
},
space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
}
Then injected via the ThemeProvider
const App = () => (
<ThemeProvider theme={theme}>
<div>
<Box
width={[
1,
1 / 2,
1 / 4,
]}
p={1}
mb={2}
bg="purple"
>
This is a tomato box, with responsive width, some padding, and margin bottom
</Box>
<div
css={css({
width: [
1,
1 / 2,
1 / 4,
],
p: 1,
mb: 2,
bg: 'purple',
})}
>
This is a tomato box, with responsive width, some padding, and margin bottom
</div>
</div>
</ThemeProvider>
)
- theme-ui.com/getting-started
- github.com/system-ui/theme-ui
- 1k stars
- 33 open issues
- 37kb bundle size
- Created with emotion + styled-system
- @types/theme-ui
- Built-in support for dark mode
Define as theme as per styled-system
const theme = {
colors: {
primary: '#000e1a',
secondary: '#fff',
purple: '#007ce0',
magenta: '#004175',
},
space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
}
Inject theme via ThemeProvider
and theme props become available via sx
prop
/** @jsx jsx */
import { jsx } from 'theme-ui'
const App = () => (
<ThemeProvider theme={theme}>
<div
sx={{
width: [
1,
1 / 2,
1 / 4,
],
p: 1,
mb: 2,
bg: 'purple',
})}
>
This is a tomato box, with responsive width, some padding, and margin bottom
</div>
</ThemeProvider>
)
But how is this different from using just styled-system
+ emotion
?
Theme UI uses @styled-system/css and the same theme spec that Styled System adheres to. Styled System is a much lower-level API that is not in any way coupled to React or Emotion. For example, Styled System works with Node.js, Vuejs, Svelte, and many other libraries. Theme UI is intended to be a higher-level abstraction specifically for use in React applications and includes features that will not likely be added to the core Styled System library.
A slightly more complex example can be found here, which from what I can see includes some extra nice-nice things like:
Layout
: the root styled component for wrapping other layout componentsContainer
: a centered area with a max-widthBox
&Flex
: are convenience components with a few style presets, similar to the ones found in Rebass.
That can be configured via theme
const theme = {
...
styles: {
Layout: {
color: 'text',
backgroundColor: 'background',
fontFamily: 'body',
lineHeight: 'body',
},
Container: {
maxWidth: 1160,
padding: 3,
},
},
}
And of course dark mode
const theme = {
initialColorMode: 'light',
colors: {
text: '#392a25',
muted: '#aaaaaa',
background: '#f8f8f8',
foreground: '#ffffff',
primary: '#92b955',
secondary: '#9f8a6d',
modes: {
dark: {
text: '#ffffff',
background: '#111111',
foreground: '#333333',
primary: '#1da1f2',
},
},
}
}