Conditionals in styled-components

October 10, 2020

One of the greatest things about styled-components is that it makes it so easy to write dynamic styles. The only drawback is that those conditionals can become pretty verbose and you might have seen other developers complain about ternary hells where their code stylesheet is suddenly filled with ? : ? : ? : ? :

This article could give you both simple and more advanced ideas on how to write tidy ternaries and at the same time take advantage of dynamic styles.

Even though following examples are limited to a certain use case, they can definitely be of inspiration for simplifying any complicated conditionals.

The OR / AND Operators

I’ll start simple by just giving a quick reminder that…
? : can sometimes be replaced by &&

//This
const Button = styled.button`
  opacity: ${props => props.disabled && "0.5"};
`

//Instead of
const Button = styled.button`
  opacity: ${props => (props.disabled ? "0.5" : "1")};
`

//because opacity defaults to 1

? : ? : can also often be replaced by ||
- Although this could seem obvious it sometimes tends to be forgotten:

//instead of this:
const Button = styled.button`
  opacity: ${props => (props.disabled ? "0.5" : props.error ? "0.5" : "1")};
`

//this here:
const Button = styled.button`
  opacity: ${props => props.disabled || (props.error && "0.5")};
`

Nested ternaries

Let’s say you have a <button/> and you want it to have a color from a theme, you could use the bracket notion to access it:

//instead of this...

const Button = styled.button`
  background-color: ${props =>
    props.primary
      ? theme.colors.mainColors.primary.background
      : props.secondary
      ? theme.colors.mainColors.secondary.background
      : theme.colors.mainColors.default.background};
`

//...you could do this:
const Button = styled.button`
  background-color: ${({ theme, nature }) =>
    theme.colors.mainColors[nature].background};
`

When you have multiple CSS properties you can also do this:
//instead of this (quite repetitive):
const Button = styled.button`
  background-color: ${({ theme, nature }) =>
    theme.colors.mainColors[nature].background};
  color: ${({ theme, nature }) => theme.colors.mainColors[nature].color};
`

//you could do like this: (notice how we dropped the back ticks/template literals):
const Button = styled.button(
  ({ theme, nature }) => css`
    color: ${theme.colors.mainColors[nature].color};
    background-color: ${theme.colors.mainColors[nature].background};
  `
)

//or even this to avoid repetitions:
const Button = styled.button`
  ${({ theme, nature }) => {
    const mainColor = theme.colors.mainColors[nature]
    return css`
      background-color: ${mainColor.background};
      color: ${mainColor.color};
    `
  }}
`

//..or you could have already defined this CSS in an object.

const colors = theme.colors.mainColors
const buttonVariants = {
  default: `background-color: ${colors.default.background}; color: ${colors.default.color};`,
  primary: `background-color: ${colors.primary.background} color: ${colors.primary.color};`,
  secondary: `background-color: ${colors.secondary.background}; color: ${colors.secondary.color}; `,
}

const Button = styled(BasicButton)`
  ${({ nature }) => buttonVariants[nature] || variants.default};
`

Styled-components is pretty unopinionated, there are almost endlessly many options of playing around with this. After all it’s just javascript.

Helper functions

//Instead of the following (which can be quite chatty) :

const Button = styled.button`
  background-color: ${props =>
    props.theme.colors.mainColors.primary.background};
`

// You can abstract a helper function that will
// automatically object-destruct your theme.
// This is possible because what's happening
// behind the scenes is getPrimaryColor(props)
const getPrimaryColor = ({
  theme: {
    colors: {
      mainColors: { primary },
    },
  },
}) => primary

const Button = styled.button`
  background-color: ${getPrimaryColor};
`

//If you'd like you could also make it take in the
//nature of the button as a variable in order to make
//the helper function more generic:

const getMainBackgroundColor = (theme, nature) =>
  theme.colors.mainColors[nature].background

const Button = styled.button`
  background-color: ${props =>
    getMainBackgroundColor(props.theme, props.nature)};
`

//Or you could do:

const getColor = (type = "background") => props => {
  return props.theme.colors.mainColors[props.nature][type]
}

const Button = styled(BasicButton)`
  background-color: ${getColor()};
  color: ${getColor("color")};
`

Final words

Now you’ve hopefully some new ideas on how to clean up your conditionals. I’ll leave two links to articles that explain what’s going on under the hood of styled-components. It’s very helpful in order to give you some ideas on how you can play around with it:

  • Here’s an article that will show you behind the scenes of SC and
  • and here’s an article from the creator of SC.

Let me know if you have some tangled ternaries that I could help you simplify, or if you’re using some pattern that you find useful. You are more than welcome to reach out to me on Twitter :)


Get more tips in my almost monthly newsletter about CSS & React!