How to change style of styled-component dynamically?

10,925

Solution 1

You need to manage every Button's state.

All solutions will different in "how" you manage buttons state (as a single object/array/etc...), the main concept is to get the button's id in order to know which state you refer to.

In the next simple example, I use a curried function to provide the button id.

Another simple solution can be with passing the id attribute to your button and querying it on button click.

const ButtonsRow = styled.div`
  display: flex;
  justify-content: space-evenly;
`;

const Button = styled.div`
  cursor: pointer;
  :hover {
    background-color: gray;
  }

  background-color: ${props => (props.selected ? 'red' : 'none')};
`;

class ButtonsContainer extends React.Component {
  state = {
    first: false,
    second: false,
    third: true
  };

  toggle = buttonName => () => {
    this.setState(prev => ({ [buttonName]: !prev[buttonName] }));
  };

  render() {
    const { first, second, third } = this.state;
    return (
      <ButtonsRow>
        <Button selected={first} onClick={this.toggle('first')}>
          People
        </Button>
        <Button selected={second} onClick={this.toggle('second')}>
          Members
        </Button>
        <Button selected={third} onClick={this.toggle('third')}>
          Games
        </Button>
      </ButtonsRow>
    );
  }
}

Edit Q-58628628-ButtonToggle

Solution 2

You have to create a variable to store the state of each button. A simpler approach may be to dynamically generate the buttons from an array and use the same to maintain the state.

class ButtonsContainer extends React.Component {
    state = {
       buttons = [{label:"People"},{label:"Members"},{label:"Games"}]
    }

    handleClick = (button) => (e) => {
      this.setState((prevState) => ({
           buttons: prevState.buttons.filter(btn => btn.label !== button.label)
                                .concat({...button,selected:!button.selected})
      })
    }

    render() {
        return(
            <ButtonsRow>
                {this.state.buttons.map(button => (<Button key={button.label} selected={button.selected} onClick={this.handleClick(button)}>{button.label}</Button>))}
            </ButtonsRow>  
        );
    }
}

export default ButtonsContainer;
Share:
10,925

Related videos on Youtube

Logan Phillips
Author by

Logan Phillips

Updated on June 04, 2022

Comments

  • Logan Phillips
    Logan Phillips almost 2 years

    I am currently learning about using styled-components in React, and having trouble with implementing this.

    I have a row of buttons (defined as divs). When a button is clicked, I want it's background to fill with a certain color. All of the other buttons should stay 'unselected'. Here is what I have so far:

    import React from 'react';
    import styles from 'styled-components';
    
    const ButtonsRow = styles.div`
        display: flex;
        justify-content: space-evenly;
    `;
    
    const Button = styles.div`
        cursor: pointer;
        :hover {
            background-color: gray;
        }
    
        background-color: ${props => props.selected ? 'red' : 'none'};
    `;
    
    class ButtonsContainer extends React.Component {
    
        handleClick = (e) => {
          // add 'selected' prop to the clicked <Button>?
        }
    
        render() {
            return(
                <ButtonsRow>
                    <Button onClick={this.handleClick}>People</Button>
                    <Button onClick={this.handleClick}>Members</Button>
                    <Button onClick={this.handleClick}>Games</Button>
                </ButtonsRow>  
            );
        }
    }
    
    export default ButtonsContainer;

    If I button is clicked, I think I wanted to give it the 'selected' prop. That way, if it has the prop, then it will fill the background color. If it doesn't have it, then it doesn't have a background color. I thought that maybe I could use state to do this, but if I were to do that, I think it would apply to every button. Thanks for any help.