0

In my ReactJS component below I'm rendering 3 buttons using React.createElement(). I want to add functionality where the button clicked on gets a 'selected' class and all the other buttons get an 'unselected' class. Furthermore, when the component firsts loads I'd like the first button ('Select All') to have the 'selected' class.

Right now I've written this button logic using jQuery but I'm wondering how I could do this in all React.

class Mychart extends React.Component {

    constructor(props) {
      super(props);
      this.state = {}
    }

    handleClick(i) {
      // for all buttons: remove 'selected' class, add 'unselected' class 
      $('.custom-btn').removeClass('selected').addClass('unselected');
      // for the button we're clicking on: remove the 'unselected' class, add 'selected' class
      $('.custom-btn[index='+i+']').removeClass('unselected').addClass('selected');
    }

    render() {
     [{label: 'Select All', label: 'Select Legacy', label: 'Select Kids'}].map((button, i) => {
       return React.createElement('button', {className: i === 0 ? 'custom-btn selected' : 'custom-btn unselected', index: i, onClick: () => {this.handleClick(i)} }, button.label)
     });
    }
}

ReactDOM.render(React.createElement(Mychart), parent);
2
  • 1
    Rather than a class, why not just use the pre-existing :focus selector? Commented Jul 13, 2021 at 17:59
  • @ControlAltDel how would I do that? Commented Jul 13, 2021 at 18:06

2 Answers 2

4

The standard React way to do this is to remember which button is the "selected" one with state (although as ControlAltDel points out, in this specific case you probably want to use CSS instead):

class Mychart extends React.Component {

    constructor(props) {
      super(props);
      this.state = {
          // *** Start with none selected
          selected: -1,
      };
    }

    handleClick(i) {
        this.setState({selected: i});
    }

    render() {
        // Get the selected one
        const {selected} = this.state;
        return [{label: 'Select All'}, {label: 'Select Legacy'}, {label: 'Select Kids'}].map((button, i) => {
            return React.createElement(
                'button',
                {
                    // *** Use the selected index
                    className: i === selected ? 'custom-btn selected' : 'custom-btn unselected',
                    key: i, // *** `key`, not `index`
                    onClick: () => {
                        this.handleClick(i);
                    }
                },
                button.label
            );
        });
    }
}

ReactDOM.render(React.createElement(Mychart), document.getElementById("root"));
.custom-btn.selected {
    color: green;
}
<div id="root"</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

(Felt very odd doing this without JSX. :-D )

Note: I had to fix a couple of errors in your code, the primary one being that you had an array with just one object with a repeated label property in it, rather than an array of objects.

In your code you were working by index so that's how I did the example above, but I would probably give each element a unique ID instead (or use label, if label is unique):

class Mychart extends React.Component {

    constructor(props) {
      super(props);
      this.state = {
          // *** Start with none selected
          selected: "",
      };
    }

    handleClick(label) {
        this.setState({selected: label});
    }

    render() {
        // Get the selected one
        const {selected} = this.state;
        return [{label: "Select All"}, {label: "Select Legacy"}, {label: "Select Kids"}].map(({label}, i) => {
            return React.createElement(
                "button",
                {
                    // *** Use the selected index
                    className: label === selected ? "custom-btn selected" : "custom-btn unselected",
                    key: label, // *** `key`, not `index`
                    onClick: () => {
                        this.handleClick(label);
                    }
                },
                label
            );
        });
    }
}

ReactDOM.render(React.createElement(Mychart), document.getElementById("root"));
.custom-btn.selected {
    color: green;
}
<div id="root"</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, and yes, there was an error w/that button array. Also this worked for me: className: i === this.state.selected (adding this.state)
0

Using CSS, you can create a style for the focused button, like:

button.custom-btn:focus {
    color: green;
}

or

button:focus {
    color: green;
}

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.