0

My state is {visibilityFilter: "completed"} or {visibilityFilter: "todo"}. Based on this I want to assign classnames to an element. Something like this,

<span {this.state.visibilityFilter=="completed"?className="active":className:""}>Completed</span>

But it's not working. I tried different variations of it,

{<span this.state.visibilityFilter=="completed"?className="active":className:"">Completed</span>}

But none of them are working. I know that it can work if I create a variable outside return statement and assign it in HTML. Like this,

let classCompleted = this.state.visibilityFilter == "completed"? "active":"";

and then,

<span className={`$(classCompleted)`}></span>

But I want to know how to do evaluate class in return statement.

2
  • 1
    This answer seems a perfect match for your question Commented Jan 8, 2017 at 11:02
  • 1
    @Icepickle: I should have realized it would be a duplicate, good find. Commented Jan 8, 2017 at 11:24

2 Answers 2

5

You're close, you just put the className part outside:

<span className={this.state.visibilityFilter=="completed" ? "active" : ""} onClick={this.handleFilter.bind(this,'completed')}>Completed</span>

Off-topic side note:

Using bind in the onClick every time means you'll re-bind every time that element is rendered. You might consider doing it once, in the component's constructor:

class YourComponent extends React.Component {
    constructor(...args) {
        super(...args);
        this.handleFilter = this.handleFilter.bind(this);
        // ...
    }
    handleFilter() {
        // ...
    }
    render() {
        return <span className={this.state.visibilityFilter=="completed" ? "active" : ""} onClick={this.handleFilter}>Completed</span>;
    }
}

Another option is to make it an arrow function, if you've enabled class properties in your transpiler (they're in the stage-2 preset in Babel as of this writing, January 2017):

class YourComponent extends React.Component {
    // ...
    handleFilter = event => {
        // ...
    };
    render() {
        return <span className={this.state.visibilityFilter=="completed" ? "active" : ""} onClick={this.handleFilter}>Completed</span>;
    }
}

Live example of that one:

class YourComponent extends React.Component {
    constructor() {
      super();
      this.state = {
        visibilityFilter: ""
      };
    }
    handleFilter = event => {
      this.setState({
        visibilityFilter: "completed"
      });
    };
    render() {
        return <span className={this.state.visibilityFilter == "completed" ? "active" : ""} onClick={this.handleFilter}>Completed</span>;
    }
}
ReactDOM.render(
  <YourComponent />,
  document.getElementById("react")
);
.active {
  color: blue;
}
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

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

4 Comments

Although that's perfectly correct, isn't classNames the better way to go, like here?
@Icepickle: Obviously one is free to use an extra library if one wants.
@T.J.Crowder Thanks for the answer and advice.
@AnuragAwasthi Please just use classNames library. I tried it with and without and it's so amazing.
3

Use classNames, A simple javascript utility for conditionally joining classNames together.

Note: I've added the state and todo classes to demonstrate working with multiple classes. btw - the comments are not valid JSX, so don't use the code as is.

<span className={
    state: true, // always 
    active: this.state.visibilityFilter === "completed", // conditional
    todo: this.state.visibilityFilter !== "todo" // conditional
}>
Completed
</span>}

Example (based on T.J. Crowder`s code):

class YourComponent extends React.Component {
    constructor() {
      super();
      this.state = {
        visibilityFilter: ""
      };
    }
    handleFilter = event => {
      this.setState({
        visibilityFilter: "completed"
      });
    };
    render() {
        return (
          <span className={classNames({
          state: true,
          active: this.state.visibilityFilter === "completed"
        })} onClick={this.handleFilter}>Completed
        </span>
       );
    }
}
ReactDOM.render(
  <YourComponent />,
  document.getElementById("react")
);
.state {
  color: red;
  cursor: pointer;
}

.active {
  color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.5/index.min.js"></script>
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

2 Comments

Thanks. But I wanted to know what was problem with my jsx.
For that you've got @T.J.Crowder answer :) I thought you might like to know that the classNames option exists.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.