139

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>
     )
  }}

7 Answers 7

257

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;
  `}
`;
Sign up to request clarification or add additional context in comments.

12 Comments

Documentation: Adapting based on props.
In TypeScript you need to use either ({ active }: any) or withProps.
It adds a false in the CSS string and can cause troubles
@LucasWillems if you use an out of date babel transpiler and react it does. React doesn't render the falsy values anymore
The conditional code shouldn't be wrapped in plain backticks, but rather should be wrapped in css``
|
71

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:

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'
  })
`

3 Comments

{ css } - 👏🏽. I didn't know about that. Where is it in the docs?
@CodeFinity it's there: styled-components.com/docs/api#css
It seems like it's working without css tag if you just return a simple string with valid styles. Please correct me if I am wrong.
25

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>

1 Comment

this is the only way worked well for me, because it contains the Type and Css function, great job!
13

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.

6 Comments

I like that syntax, but are you sure it works for non-boolean checks? (ex. props => props.foo === "bar") doesn't seem to work for me to check a specific value
It works as I use the syntax quite often. You might want to put a console.log in there to check that "foo" is actually defined.
Could you please elaborate? I don't get why it works, is that specific to how Styled Components work?
yes, I confirm that TS complains when I try to do something like: ${(props) => props.$isSelected} { ...
this syntax doesn't work, I past the same code to my project, but get some eerros.
|
6

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

Comments

1

This answer is for all the people who are using their official guide. According to their official docs we can do conditional rendering like this but in my case it didn't work


const Button = styled.button<{ $primary?: boolean; }>`
  /* Adapt the colors based on primary prop */
  background: ${props => props.$primary ? "#BF4F74" : "white"};
  color: ${props => props.$primary ? "white" : "#BF4F74"};

  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid #BF4F74;
  border-radius: 3px;
`;

render(
  <div>
    <Button>Normal</Button>
    <Button $primary>Primary</Button>
  </div>
);

This is how I solved that


export const Icon = styled.img`
 ${({ password }) => password && `
    cursor: pointer;
  `}
`

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.