510

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" data-toggle="dropdown" aria-expanded="false">
                      Bulk Actions <span className="caret"></span>
                    </button>
                    <ul className="dropdown-menu" role="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?

2
  • You may also wish to consider react-bootstrap, since this abstracts some of the class stuff into component properties, making what you're trying to do a little easier. Commented Jun 14, 2017 at 17:31
  • Just use clsx these days I'd say :) Commented Oct 7, 2024 at 10:40

25 Answers 25

871

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.

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

6 Comments

Thanks! I had to modify it slightly because for some reason it wasn't outputting btn-group pull-right at all. Just show or hidden.
This is particularly helpful in certain cases where classnames might not be appropriate. If you are in your render function and you have a map, you might only know whether you want to add a class at the time you are rendering it, so this answer is quite useful for that.
great alternative instead of having a bunch of conditional templates in your render or return
@apexdodge what modification you had to do. I have the same issue.
@RamY One way is to put all the classes inside the conditional this.props.showBulkActions ? 'btn-group pull-right show' : 'btn-group pull-right hidden'). Not elegant but it works.
|
132

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

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 a performance improvement, you can look into clsx as an alternative.

5 Comments

Could you elaborate on classNames utility being the "currently recommended approach"? Is that captured in some well-regarded best practices document somewhere? Or just sort of the word of mouth around React and classNames at the moment?
@anied At the time of writing it was recommended in official React documentation: web.archive.org/web/20160602124910/http://facebook.github.io:80/…
It is still mentioned in latest documentation: "If you often find yourself writing code like this, classnames package can simplify it."
As of 2021, instead of classnames you might want to try clsx
classnames is still mentioned here - "To make this more readable, you can use a tiny helper library like classnames"
120

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 Comment

Be careful with the second approach, especially in large codebases, as it makes the class strings less greppable. For example, if someone searches for s-is-shown or s-is-hidden in the codebase, they won't find this code.
28

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 Comments

If you are conditionally rendering a single className inline and don't want a class to appear for one of the conditions, you can return null or undefined instead of an empty string. Example: className={condition ? 'red' : null} or className={condition ? 'red' : undefined} It's better to keep your markup clean rather than having elements appear like <div class> or `<div class="null">
@AnthonyAvila true, also its better to use classnames npmjs.com/package/classnames to avoid printing extra empty spaces.
21

You can use here String literals

const Angle = ({show}) => {

   const angle = `fa ${show ? 'fa-angle-down' : 'fa-angle-right'}`;

   return <i className={angle} />
}

Comments

17

Replace:

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

with:

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

Comments

15

In case you will need only one optional class name:

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

2 Comments

This will append false class when condition fails.
instead of "" in the ternary use null, if not, the class property is set in the element, with null not, it's better
14

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

Comments

14

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

Comments

13

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 Comments

please expand upon this, what is condition?
const condition = (1 === 1);
12

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

Comments

11
<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')  )

Comments

10

simply use this approach--

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

this is much more neat and clean.

Comments

10

I have tried to tailored my answer to include all the best possible solution in the post

There are many different ways of getting this done.

1. Inline inside the class

<div className={`... ${this.props.showBulkActions ? 'show' : 'hidden'}`}>
  ...
</div>

2. Using the values

var btnClass = classNames(
  ...
  {
    'show': this.props.showBulkActions,
    'hidden': !this.props.showBulkActions
  }
);

3. Using a variable

let dependentClass = this.props.showBulkActions ? 'show' : 'hidden';

className={`... ${dependentClass }`}

4. Using clsx

<div className={clsx('...',`${this.props.showBulkActions ? 'show' : 'hidden'}`)}>
  ...
</div>

Comments

8

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(' ')}/>

Comments

4

you can use this:

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

Comments

3

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

Comments

1

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

Comments

1

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

Comments

0

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"

Comments

0

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

Comments

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="http://imageurl" alt="Avatar" class="img-bot">

Comments

0

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.

Comments

0
<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.

Comments

0

A more modern answer to this question.

If you would only use JS, then you could do something like the following:

const Box = ({ status, children }) => {
  let classNames = ['box'];

  if (status === 'INFO') {
    classNames.push('box-info');
  }

  if (status === 'WARNING') {
    classNames.push('box-warning');
  }

  if (status === 'ERROR') {
    classNames.push('box-error');
  }

  return (
    <div className={classNames.join(' ')}>
      {children}
    </div>
  );
}

But I'd recommend using a popular library like clsx for it:

import cs from 'clsx';

const Box = ({ status, children }) => {
  const classNames = cs('box', {
    'box-info': status === 'INFO',
    'box-warning': status === 'WARNING',
    'box-error': status === 'ERROR',
  });

  return (
    <div className={classNames}>
      {children}
    </div>
  );
}

More about this here.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.