Home » Javascript » How to add multiple classes to a ReactJS Component

How to add multiple classes to a ReactJS Component

Posted by: admin November 30, 2017 Leave a comment

Questions:

I am new to ReactJS and JSX and I am having a little problem with the code below.

I am trying to add multiple classes to the classNames attribute on each li:

<li key={index} className={activeClass, data.class, "main-class"}></li>

My React component is:

var AccountMainMenu = React.createClass({

getInitialState: function(){
    return { focused: 0 };
},

clicked: function(index){
    this.setState({focused: index});
},

render: function() {

    var self = this;
    var accountMenuData = [
            {
                name : "My Account",
                icon : "icon-account"                       
            },
            {
                name:"Messages",
                icon:"icon-message" 
            },
            {
                name:"Settings",
                icon:"icon-settings"
            }
            /*{
                name:"Help &amp; Support &nbsp; <span class='font-awesome icon-support'></span>(888) 664.6261",
                listClass:"no-mobile last help-support last"
            }*/
        ];

    return (
        <div className="acc-header-wrapper clearfix">   
            <ul className="acc-btns-container">
                { 
                    accountMenuData.map(function(data, index) {

                        var activeClass = '';

                        if(self.state.focused == index){
                            activeClass = 'active';
                        }

                        return (
                            <li key={index} className={activeClass} onClick={self.clicked.bind(self, index)}>
                                <a href="#" className={data.icon}>{data.name}</a>
                            </li>
                        )
                    })
                }     
            </ul>
        </div>

    );

}
});

ReactDOM.render(
  <AccountMainMenu />,
  document.getElementById('app-container')
);
Answers:

I use classnames. For example:

...
    var liClasses = classNames({
      'main-class': true,
      'activeClass': self.state.focused === index
    });

    return (<li className={liClasses}>{data.name}</li>);
...

Questions:
Answers:

I use ES6. For example:

const error = this.state.valid ? '' : 'error';
const classes = `${error} form-control input-lg round-lg`;

And then just render it:

<input className={classes} />

Questions:
Answers:

Just use JavaScript.

<li className={[activeClass, data.klass, "main-class"].join(' ')} />

If you want to add classes based keys and values in an object you can use the following:

function classNames(classes) {
  return Object.entries(classes)
    .filter(([key, value]) => value)
    .map(([key, value]) => key)
    .join(' ');
}

const classes = {
  'maybeClass': true,
  'otherClass': true,
  'probablyNotClass': false,
};

const myClassNames = classNames(classes);
// Output: "maybeClass otherClass"

<li className={myClassNames} />

Or even simpler:

const isEnabled = true;
const isChecked = false;

<li className={[isEnabled && 'enabled', isChecked && 'checked'].filter(e => !!e).join(' ')} />
// Output:
// <li className={'enabled'} />

Questions:
Answers:

Concat

No need to be fancy I am using CSS modules and it’s easy

import style from '/css/style.css';

<div className={style.style1+ ' ' + style.style2} />

This will result in:

<div class="src-client-css-pages-style1-selectionItem src-client-css-pages-style2">

In other words, both styles


UPDATE – Using an npm package to handle classes in react

Whilst for me personally this is more than enough, sometimes you might want to add logic to your classes and it can get a little messy.

Npm Classes – Is an npm package that handles classes easily for you:

classNames('foo', 'bar'); // => 'foo bar' 
classNames('foo', { bar: true }); // => 'foo bar' 
classNames({ 'foo-bar': true }); // => 'foo-bar' 
classNames({ 'foo-bar': false }); // => '' 
classNames({ foo: true }, { bar: true }); // => 'foo bar' 
classNames({ foo: true, bar: true }); // => 'foo bar' 

Real world example

var Button = React.createClass({
  // ... 
  render () {
    var btnClass = classNames({
      'btn': true,
      'btn-pressed': this.state.isPressed,
      'btn-over': !this.state.isPressed && this.state.isHovered
    });
    return <button className={btnClass}>{this.props.label}</button>;
  }
});

Questions:
Answers:

You can create an element with multiple class names like this:

<li className="class1 class2 class3">foo</li>

Naturally, you can use a string containing the class names and manipulate this string to update the class names of the element.

var myClassNammes = 'class1 class2 class3';
...
<li className={myClassNames}>foo</li>

Questions:
Answers:

Maybe classnames can help you.

var classNames = require('classnames');
classNames('foo', {'xx-test': true, bar: false}, {'ox-test': false}); // => 'foo xx-test'

Questions:
Answers:

Vanilla JS

No need for external libraries – just use ES6 template strings:

<i className={`${styles['foo-bar-baz']} fa fa-user fa-2x`}/>

Questions:
Answers:

This is how you can do that with ES6:

className = {`
      text-right
      ${itemId === activeItemId ? 'active' : ''}
      ${anotherProperty === true ? 'class1' : 'class2'}
`}

You can list multiple classes and conditions and also you can include static classes. It is not necessary to add an additional library.

Good luck 😉

Questions:
Answers:

Late to the party, but why use third party for such a simple problem?

You could either do it as @Huw Davies mentioned – the best way

1. <i className={`${styles['foo-bar-baz']} fa fa-user fa-2x`}/>
2. <i className={[styles['foo-bar-baz'], 'fa fa-user', 'fa-2x'].join(' ')}

Both are good. But writing can become complex for a large app. To make it optimal, I do the same above things but put it in a helper class

Using my below helper function, allows me to keep the logic separate for future editing, and also gives me multiple ways to add the classes

classNames(styles['foo-bar-baz], 'fa fa-user', 'fa-2x')

or

classNames([styles['foo-bar-baz], 'fa fa-user', 'fa-2x'])

This is my helper function below. I’ve put it in a helper.js where I keep all my common methods. Being such a simple function, I avoided using 3rd party to keep control

export function classNames (classes) {
    if(classes && classes.constructor === Array) {
        return classes.join(' ')
    } else if(arguments[0] !== undefined) {
        return [...arguments].join(' ')
    }
    return ''
}

Questions:
Answers:

Just adding, we can filter out empty strings.

className={[
    'read-more-box',
    this.props.className,
    this.state.isExpanded ? 'open' : 'close',
].filter(x => !!x).join(' ')}

Questions:
Answers:

I use rc-classnames package.

// ES6
import c from 'rc-classnames';

// CommonJS
var c = require('rc-classnames');

<button className={c('button', {
  'button--disabled': isDisabled,
  'button--no-radius': !hasRadius
})} />

You can add classes in any format (Array, Object, Argument). All truthy values from arrays or Arguments plus keys in objects that equal to true get merged together.

for example:

ReactClassNames('a', 'b', 'c') // => "a b c"
ReactClassNames({ 'a': true, 'b': false, c: 'true' }) // => "a c"
ReactClassNames(undefined, null, 'a', 0, 'b') // => "a b"

Questions:
Answers:

Using facebook’s TodoTextInput.js example

render() {
    return (
      <input className={
        classnames({
          edit: this.props.editing,
          'new-todo': this.props.newTodo
        })}
        type="text"
        placeholder={this.props.placeholder}
        autoFocus="true"
        value={this.state.text}
        onBlur={this.handleBlur}
        onChange={this.handleChange}
        onKeyDown={this.handleSubmit} />
    )
  } 

replacing classnames with plain vanilla js code will look like this:

render() {
    return (
      <input
        className={`
          ${this.props.editing ? 'edit' : ''} ${this.props.newTodo ? 'new-todo' : ''}
        `}
        type="text"
        placeholder={this.props.placeholder}
        autoFocus="true"
        value={this.state.text}
        onBlur={this.handleBlur}
        onChange={this.handleChange}
        onKeyDown={this.handleSubmit} />
    )
  }

Questions:
Answers:

That’s what I do:

Component:

const Button = ({ className }) => (
  <div className={ className }> </div>
);

Calling Component:

<Button className = 'hashButton free anotherClass' />