Styling

React does not have an opinion about how styles are defined; if in doubt, a good starting point is to define your styles in a separate *.css file as usual and refer to them using className.

React docs

Global CSS

the ol' reliable

  • just import some CSS
  • no scoping
  • have to use BEM
import React, { FC, useState } from 'react'
import './global.css'
import { Slider } from './slider'

export const Global: FC = () => {
  const [value, setValue] = useState(100)

  return (
    <div className="global__wrapper">
      <Slider value={value} onChange={setValue} />
      <div className="global__circle" style={{ fontSize: `${value * 0.01}em` }}>
        awesome circle
      </div>
    </div>
  )
}

export default <Global />
awesome circle

CSS Modules

  • just import some CSS
  • must be named *.module.css
  • classes automatically scoped, worry free naming
  • CSS bundled with component
  • short class names in production
  • less dead CSS
import React, { FC, useState } from 'react'
import classes from './example.module.css'
import { Slider } from './slider'

export const Module: FC = () => {
  const [value, setValue] = useState(100)

  return (
    <div className={classes.wrapper}>
      <Slider value={value} onChange={setValue} />
      <div className={classes.circle} style={{ fontSize: `${value * 0.01}em` }}>
        awesome circle
      </div>
    </div>
  )
}

export default <Module />
awesome circle
  • note that both CSS approaches have to use the style prop for dynamic styles

CSS in JS

  • common pattern in React apps provided by libraries

  • styled-components most popular

    • Automatic critical CSS
    • No class name bugs
    • Easier deletion of CSS
    • Simple dynamic styling
    • Painless maintenance
    • Automatic vendor prefixing
  • fantastic for dynamic styling

  • component fully contained in single file

  • needs extension for syntax highlighting

import React, { FC, useState } from 'react'
import styled from 'styled-components'
import { Slider } from './slider'

const Wrapper = styled.div`
  min-height: 250px;
  min-width: 250px;
`

const Circle = styled.div<{ fontSize: number }>`
  align-items: center;
  background-color: dodgerblue;
  border-radius: 99999px;
  color: aliceblue;
  display: flex;
  flex-direction: column;
  font-family: Arial, Helvetica, sans-serif;
  font-size: ${(props) => props.fontSize}em;
  height: 10em;
  justify-content: center;
  transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
  width: 10em;
`

export const Styled: FC = () => {
  const [value, setValue] = useState(100)

  return (
    <Wrapper>
      <Slider value={value} onChange={setValue} />
      <Circle fontSize={value * 0.01}>awesome circle</Circle>
    </Wrapper>
  )
}

export default <Styled />
awesome circle

P.S.

  • it doesn’t matter which approach you use, but don’t mix them