conditional rendering in styled components

ReactjsStyled Components

Reactjs Problem Overview


How can I use conditional rendering in styled-components to set my button class to active using styled-components in React?

In css I would do it similarly to this:

<button className={this.state.active && 'active'}
      onClick={ () => this.setState({active: !this.state.active}) }>Click me</button>

In styled components if I try to use '&&' in the classname it doesn't like it.

import React from 'react'
import styled from 'styled-components'

const Tab = styled.button`
  width: 100%;
  outline: 0;
  border: 0;
  height: 100%;
  justify-content: center;
  align-items: center;
  line-height: 0.2;
`

export default class Hello extends React.Component {
  constructor() {
    super()
    this.state = {
      active: false
    }  
    this.handleButton = this.handleButton.bind(this)
}
  
  handleButton() {
    this.setState({ active: true })
  }
  
  render() {
     return(
       <div>
         <Tab onClick={this.handleButton}></Tab>
       </div>
     )
  }}

Reactjs Solutions


Solution 1 - Reactjs

You can simply do this

<Tab active={this.state.active} onClick={this.handleButton}></Tab>

And in your styles something like this:

const Tab = styled.button`
  width: 100%;
  outline: 0;
  border: 0;
  height: 100%;
  justify-content: center;
  align-items: center;
  line-height: 0.2;

  ${({ active }) => active && `
    background: blue;
  `}
`;

Solution 2 - Reactjs

I didn't notice any && in your example, but for conditional rendering in styled-components you do the following:

// Props are component props that are passed using <StyledYourComponent prop1="A" prop2="B"> etc
const StyledYourComponent = styled(YourComponent)`
  background: ${props => props.active ? 'darkred' : 'limegreen'}
`

In the case above, background will be darkred when StyledYourComponent is rendered with active prop and limegreen if there is no active prop provided or it is falsy Styled-components generates classnames for you automatically :)

If you want to add multiple style properties you have to use css tag, which is imported from styled-components:

I didn't notice any && in your example, but for conditional rendering in styled-components you do the following:

import styled, { css } from 'styled-components'
// Props are component props that are passed using <StyledYourComponent prop1="A" prop2="B"> etc
const StyledYourComponent = styled(YourComponent)`
  ${props => props.active && css`
     background: darkred; 
     border: 1px solid limegreen;`
  }
`

OR you may also use object to pass styled, but keep in mind that CSS properties should be camelCased:

import styled from 'styled-components'
// Props are component props that are passed using <StyledYourComponent prop1="A" prop2="B"> etc
const StyledYourComponent = styled(YourComponent)`
  ${props => props.active && ({
     background: 'darkred',
     border: '1px solid limegreen',
     borderRadius: '25px'
  })
`

Solution 3 - Reactjs

Here is an simple example with TypeScript:

import * as React from 'react';
import { FunctionComponent } from 'react';
import styled, { css } from 'styled-components';

interface IProps {
  isProcessing?: boolean;
  isDisabled?: boolean;
  onClick?: () => void;
}

const StyledButton = styled.button<IProps>`
  width: 10rem;
  height: 4rem;
  cursor: pointer;
  color: rgb(255, 255, 255);
  background-color: rgb(0, 0, 0);

  &:hover {
    background-color: rgba(0, 0, 0, 0.75);
  }

  ${({ disabled }) =>
    disabled &&
    css`
      opacity: 0.5;
      cursor: not-allowed;
    `}

  ${({ isProcessing }) =>
    isProcessing &&
    css`
      opacity: 0.5;
      cursor: progress;
    `}
`;

export const Button: FunctionComponent<IProps> = ({
  children,
  onClick,
  isProcessing,
}) => {
  return (
    <StyledButton
      type="button"
      onClick={onClick}
      disabled={isDisabled}
      isProcessing={isProcessing}
    >
      {!isProcessing ? children : <Spinner />}
    </StyledButton>
  );
};
<Button isProcessing={this.state.isProcessing} onClick={this.handleClick}>Save</Button>

Solution 4 - Reactjs

I haven't seen this syntax, which I feel is the cleanest when you need to make a complete block conditional:

const StyledButton = styled(button)`
	display: flex;
	background-color: white;

	${props => !props.disabled} {
		&:hover {
			background-color: red;
		}

		&:active {
			background-color: blue;
		}
	}
`;

So there's no need to close/open ticks to get it working.

Solution 5 - Reactjs

If your state is defined in your class component like this:

class Card extends Component {
  state = {
    toggled: false
  };
  render(){
    return(
      <CardStyles toggled={this.state.toggled}>
        <small>I'm black text</small>
        <p>I will be rendered green</p>
      </CardStyles>
    )
  }
}

Define your styled-component using a ternary operator based on that state

const CardStyles = styled.div`
  p {
    color: ${props => (props.toggled ? "red" : "green")};
  }
`

it should render just the <p> tag here as green.

This is a very sass way of styling

Solution 6 - Reactjs

It seems to be possible to use classNames as well, by applying them conditionally:

const BoxClassname = styled.div.attrs((props) => ({
  className: clsx(props.$primary && "primary")
}))`
  background: #000;
  height: 1px;
  width: 50px;
  &.primary {
    background: pink;
  }
`;

/*
// You could also use a second component instead of .attrs
export const BoxClassname = (props) => {
  return (
    <BoxClassnameWrapper
      className={clsx(props.$primary && "primary")}
      {...props}
    />
  );
};
*/

What I like in this syntax is that you don't mix JS and CSS too much.

Limitation is that it seems slower, see this demo code sandbox for a perf comparison. I don't really get why though :/ because logically.

I had this idea after reading Josh Comeau take on using CSS variables in Styled Components.

  • CSS variables let's you configure... variables (switching colors etc.)
  • Logically, classNames + CSS selectors let's you define conditions

After all, this logic exists in CSS already, className are already meant for handling conditional rendering. Styled Components helps keeping the styles cleanly isolated and handle advanced scenarios, but I don't like it meddling too much with the styles.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiontom harrisonView Question on Stackoverflow
Solution 1 - ReactjsJoão CunhaView Answer on Stackoverflow
Solution 2 - Reactjsasn007View Answer on Stackoverflow
Solution 3 - ReactjsSaleh MuhammadView Answer on Stackoverflow
Solution 4 - ReactjslaurentView Answer on Stackoverflow
Solution 5 - ReactjsVincent TangView Answer on Stackoverflow
Solution 6 - ReactjsEric BurelView Answer on Stackoverflow