I want to conditionally show and hide this button group depending on what is passed in from the parent component which looks like this:

<TopicNav showBulkActions={this.__hasMultipleSelected} /> 

....

__hasMultipleSelected: function() { return false; //return true or false depending on data } 

....

var TopicNav = React.createClass({ render: function() { return ( <div className="row"> <div className="col-lg-6"> <div className="btn-group pull-right {this.props.showBulkActions ? 'show' : 'hidden'}"> <button type="button" className="btn btn-default dropdown-toggle" aria-expanded="false"> Bulk Actions <span className="caret"></span> </button> <ul className="dropdown-menu"> <li><a href="#">Merge into New Session</a></li> <li><a href="#">Add to Existing Session</a></li> <li className="divider"></li> <li><a href="#">Delete</a></li> </ul> </div> </div> </div> ); } }); 

Nothing is happening however, with the {this.props.showBulkActions ? 'show' : 'hidden'}. Am I doing anything wrong here?

1

23 Answers

The curly braces are inside the string, so it is being evaluated as string. They need to be outside, so this should work:

<div className={"btn-group pull-right " + (this.props.showBulkActions ? 'show' : 'hidden')}> 

Note the space after "pull-right". You don't want to accidentally provide the class "pull-rightshow" instead of "pull-right show". Also the parentheses needs to be there.

6

As others have commented, classnames utility is the currently recommended approach to handle conditional CSS class names in ReactJs.

In your case, the solution will look like:

var btnGroupClasses = classNames( 'btn-group', 'pull-right', { 'show': this.props.showBulkActions, 'hidden': !this.props.showBulkActions } ); 

...

<div className={btnGroupClasses}>...</div> 

As a side note, I would suggest you to try to avoid using both show and hidden classes, so the code could be simpler. Most likely, you don't need to set a class for something to be shown by default.

2021 addendum: for performance improvement, you can look into clsx as an alternative.

4

If you are using a transpiler (such as Babel or Traceur) you can use the new ES6 "template strings".

Here is the answer of @spitfire109, modified accordingly:

<div className={`btn-group pull-right ${this.props.showBulkActions ? 'shown' : 'hidden'}`}> 

This approach allows you to do neat things like that, rendering either s-is-shown or s-is-hidden:

<div className={`s-${this.props.showBulkActions ? 'is-shown' : 'is-hidden'}`}> 
1

You can use here String literals

const Angle = ({show}) => { const angle = `fa ${show ? 'fa-angle-down' : 'fa-angle-right'}`; return <i className={angle} /> } 

you can simply do the following for example.

let classNameDependsOnCondtion = i18n.language == 'en' ? "classname" : ""; className={`flex flex-col lg:flex-row list-none ${classNameDependsOnCondtion }`} 

OR

className={`flex flex-col lg:flex-row list-none ${i18n.language == 'en' ? "classname" : ""}`} 
2

In case you will need only one optional class name:

<div className={"btn-group pull-right " + (this.props.showBulkActions ? "show" : "")}> 
2

Expending on @spitfire109's fine answer, one could do something like this:

rootClassNames() { let names = ['my-default-class']; if (this.props.disabled) names.push('text-muted', 'other-class'); return names.join(' '); } 

and then within the render function:

<div className={this.rootClassNames()}></div> 

keeps the jsx short

Or use npm classnames. It is very easy and useful especially for constructing the list of classes

Replace:

<div className="btn-group pull-right {this.props.showBulkActions ? 'show' : 'hidden'}">` 

with:

<div className={`btn-group pull-right ${this.props.showBulkActions ? 'show' : 'hidden'}`} 

You can use ES6 arrays instead of classnames. The answer is based on Dr. Axel Rauschmayer article: Conditionally adding entries inside Array and object literals.

<div className={[ "classAlwaysPresent", ...Array.from(condition && ["classIfTrue"]) ].join(" ")} /> 
2

2019:

React is lake a lot of utilities. But you don't need any npm package for that. just create somewhere the function classnames and call it when you need it;

function classnames(obj){ return Object.entries(obj).filter( e => e[1] ).map( e=>e[0] ).join(' '); } 

or

function classnames(obj){ return Object.entries(obj).map( ([cls,enb]) => enb? cls: '' ).join(' '); } 

example

 stateClass= { foo:true, bar:false, pony:2 } classnames(stateClass) // return 'foo pony' 
 <div className="foo bar {classnames(stateClass)}"> some content </div> 

Just For Inspiration

declaring helper DOM element and using it native toggle method:

(DOMToken​List)classList.toggle(class,condition)

example:

const classes = document.createElement('span').classList; function classstate(obj){ for( let n in obj) classes.toggle(n,obj[n]); return classes; } 

More elegant solution, which is better for maintenance and readability:

const classNames = ['js-btn-connect']; if (isSelected) { classNames.push('is-selected'); } <Element className={classNames.join(' ')}/> 
1

you can use this:

<div className={"btn-group pull-right" + (this.props.showBulkActions ? ' show' : ' hidden')}> 

This is useful when you have more than one class to append. You can join all classes in array with a space.

const visibility = this.props.showBulkActions ? "show" : "" <div className={["btn-group pull-right", visibility].join(' ')}> 
<div className={['foo', condition && 'bar'].filter(Boolean).join(' ')} /> 

.filter(Boolean) removes "falsey" values from the array. Since class names must be strings, anything other than that would not be included in the new filtered array.

console.log( ['foo', true && 'bar'].filter(Boolean).join(' ') ) console.log( ['foo', false && 'bar'].filter(Boolean).join(' ') )

Above written as a function:

const cx = (...list) => list.filter(Boolean).join(' ') // usage: <div className={cx('foo', condition && 'bar')} /> 
var cx = (...list) => list.filter(Boolean).join(' ') console.log( cx('foo', 1 && 'bar', 1 && 'baz') ) console.log( cx('foo', 0 && 'bar', 1 && 'baz') ) console.log( cx('foo', 0 && 'bar', 0 && 'baz') )

This would work for you

var TopicNav = React.createClass({ render: function() { let _myClasses = `btn-group pull-right {this.props.showBulkActions?'show':'hidden'}`; return ( ... <div className={_myClasses}> ... </div> ); } }); 

Reference to @split fire answer, we can update it with template literals, which is more readable,For reference Checkout javascript template literal

<div className={`btn-group pull-right ${this.props.showBulkActions ? 'show' : 'hidden'}`}> 

simply use this approach--

<div className={`${this.props.showActions ? 'shown' : 'hidden'}`}> 

this is much more neat and clean.

You can use this npm package. It handles everything and has options for static and dynamic classes based on a variable or a function.

// Support for string arguments getClassNames('class1', 'class2'); // support for Object getClassNames({class1: true, class2 : false}); // support for all type of data getClassNames('class1', 'class2', null, undefined, 3, ['class3', 'class4'], { class5 : function() { return false; }, class6 : function() { return true; } }); <div className={getClassNames('show', {class1: true, class2 : false})} /> // "show class1" 

Based on the value of this.props.showBulkActions you can switch classes dynamically as follows.

<div ...{...this.props.showBulkActions ? { className: 'btn-group pull-right show' } : { className: 'btn-group pull-right hidden' }}> 
0

I would like to add that you can also use a variable content as a part of the class

<img src={src} alt="Avatar" className={"img-" + messages[key].sender} /> 

The context is a chat between a bot and a user, and the styles change depending of the sender, this is the browser result:

<img src="" alt="Avatar"> 
<div className={"h-3 w-3 rounded-full my-auto " + (index.endDate ==="present"? "bg-green-500":"bg-red-500")}></div> 

Don't Forget to add an extra space after the static class names.

A function to return the correct class based on a param (if present)

 getClass(param){ let podClass = 'classA' switch(param.toLowerCase()){ case 'B': podClass = 'classB' break; case 'C': podClass = 'classC' break; } return podClass } 

Now just invoke this function from the div where the corresponding class is to be applied.

 <div className={anyOtherClass + this.getClass(param)} 

I successfully used this logic to apply the correct color to my bootstrap table rows.