[javascript] How to add multiple classes to a ReactJS Component?

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 className 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"));

This question is related to javascript css reactjs ecmascript-6

The answer is


You can use arrays and then join them using space.

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

This will result in :

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

Use https://www.npmjs.com/package/classnames

import classNames from 'classnames';

  1. Can use multiple classes using comas seperated:

    <li className={classNames(classes.tableCellLabel, classes.tableCell)}>Total</li>
    
  2. Can use multiple classes using comas separated with condition:

    <li className={classNames(classes.buttonArea, !nodes.length && classes.buttonAreaHidden)}>Hello World</li> 
    

Using array as props to classNames will also work, but gives warning e.g.

className={[classes.tableCellLabel, classes.tableCell]}

Just use a comma!

const useStyles = makeStyles((theme) => ({
 rightAlign: {
  display: 'flex',
  justifyContent: 'flex-end',
 },
 customSpacing: {
  marginTop: theme.spacing(2.5),
 },
)};

<div className={(classes.rightAlign, classes.customSpacing)}>Some code</div>

I know this is a late answer, but I hope this will help someone.

Consider that you have defined following classes in a css file 'primary', 'font-i', 'font-xl'

  • The first step would be to import the CSS file.
  • Then

_x000D_
_x000D_
<h3 class = {` ${'primary'} ${'font-i'} font-xl`}> HELLO WORLD </h3>
_x000D_
_x000D_
_x000D_

would do the trick!

For more info: https://www.youtube.com/watch?v=j5P9FHiBVNo&list=PLC3y8-rFHvwgg3vaYJgHGnModB54rxOk3&index=20


You could do the following:

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

A short and simple solution, hope this helps.


I don't think we need to use an external package for just adding multiple classes.

I personally use

<li className={`li active`}>Stacy</li>

or

<li className={`li ${this.state.isActive ? 'active' : ''}`}>Stacy<li>

or

<li className={'li ' + (this.state.isActive ? 'active' : '') }>Stacy<li>

the second and third one in case you need to add or remove classes conditionally.


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

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

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

Conditionals

It would be easy to use the same idea with if's

const class1 = doIHaveSomething ? style.style1 : 'backupClass';

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

ES6

For the last year or so I have been using the template literals, so I feel its worth mentioning, i find it very expressive and easy to read:

`${class1} anotherClass ${class1}`

I use ES6 template literals. For example:

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

And then just render it:

<input className={classes} />

One-liner version:

<input className={`form-control round-lg ${this.state.valid ? '' : 'error'}`} />

clsx makes this simple!

"The clsx function can take any number of arguments, each of which can be an Object, Array, Boolean, or String."

-- clsx docs on npmjs.com

Import it:

import clsx from 'clsx'

Use it:

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

I usually use it like this : (in your case)

    <li  key={index} className={
        "component " +
        `${activeClass? activeClass: " not-an-active-class "}` +
        `${data.class? " " + data.class : " no-data-class "}`
   } />

When it comes to JSX and (usually) we have some json... than you loop it ... component.map, plus some conditional to check if json property exists to render class name depending on property value from JSON. In example below component_color and component_dark_shade are properties from component.map()

   <div className={
        "component " +
        `${component_color? component_color: " no-color "}` +
        `${component_dark_shade? " " + component_dark_shade : " light "}`
   }/>

Output : <div class="component no-color light" .... Or: <div class="component blue dark" .... depending on values from map...


That's what I do:

Component:

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

Calling Component:

<Button className = 'hashButton free anotherClass' />

I am using React 16.6.3 and @Material UI 3.5.1, and is able to use arrays in className like className={[classes.tableCell, classes.capitalize]}

So in your example, the following would be similar.

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

If you don't feel like importing another module, this function works like the classNames module.

function classNames(rules) {
    var classes = ''

    Object.keys(rules).forEach(item => {    
        if (rules[item])
            classes += (classes.length ? ' ' : '') + item
    })

    return classes
} 

You can use it like this:

render() {
    var classes = classNames({
        'storeInfoDiv': true,  
        'hover': this.state.isHovered == this.props.store.store_id
    })   

    return (
        <SomeComponent style={classes} />
    )
}

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"

Just adding, we can filter out empty strings.

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

Vanilla JS

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

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

When I have many varying classes, I have found the following to be useful.

The filter removes any of the null values and the join puts all the remaining values into a space separated string.

const buttonClasses = [
    "Button", 
    disabled ? "disabled" : null,
    active ? "active" : null
].filter((class) => class).join(" ")

<button className={buttonClasses} onClick={onClick} disabled={disabled ? disabled : false}>

Maybe classnames can help you.

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

You can create an element with multiple class names like this, I tryed these both way, its working fine...

If you importing any css then you can follow this way : Way 1:

import React, { Component, PropTypes } from 'react';
import csjs from 'csjs';
import styles from './styles';
import insertCss from 'insert-css';
import classNames from 'classnames';
insertCss(csjs.getCss(styles));
export default class Foo extends Component {
  render() {
    return (
      <div className={[styles.class1, styles.class2].join(' ')}>
        { 'text' }
      </div>
    );
  }
}

way 2:

import React, { Component, PropTypes } from 'react';
import csjs from 'csjs';
import styles from './styles';
import insertCss from 'insert-css';
import classNames from 'classnames';
insertCss(csjs.getCss(styles));
export default class Foo extends Component {
  render() {
    return (
      <div className={styles.class1 + ' ' + styles.class2}>
        { 'text' }
      </div>
    );
  }
}

**

If you applying css as internal :

_x000D_
_x000D_
const myStyle = {_x000D_
  color: "#fff"_x000D_
};_x000D_
_x000D_
// React Element using Jsx_x000D_
const myReactElement = (_x000D_
  <h1 style={myStyle} className="myClassName myClassName1">_x000D_
    Hello World!_x000D_
  </h1>_x000D_
);_x000D_
_x000D_
ReactDOM.render(myReactElement, document.getElementById("app"));
_x000D_
.myClassName {_x000D_
  background-color: #333;_x000D_
  padding: 10px;_x000D_
}_x000D_
.myClassName1{_x000D_
  border: 2px solid #000;_x000D_
}
_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.0/umd/react.production.min.js"></script>_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.0/umd/react-dom.production.min.js"></script>_x000D_
<div id="app">_x000D_
  _x000D_
</div>
_x000D_
_x000D_
_x000D_


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



Create a function like this

function cssClass(...c) {
  return c.join(" ")
}

Call it when needed.

<div className={cssClass("head",Style.element,"black")}><div>

for more classes adding

... className={`${classes.hello} ${classes.hello1}`...

This can be achieved with ES6 template literals:

<input className={`base-input-class ${class1} ${class2}`}>

(edited for clarity)


It can be done with https://www.npmjs.com/package/clsx :

https://www.npmjs.com/package/clsx

First install it:

npm install --save clsx

Then import it in your component file:

import clsx from  'clsx';

Then use the imported function in your component:

<div className={ clsx(classes.class1, classes.class2)}>

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>


Generally people do like

<div className={  ['head', style.class1 , Style.class2].join(' ')  }><div>

But you can choose to Create a function to do this job

function joinAll(...classes) {
  return classes.join(" ")
}

then call it like:-

<div className={joinAll('head', style.class1 , style.class2)}><div>

If you wanna use a double conditional css module is always somehow confusing so i would advise you to follow this pattern

import styles from "./styles.module.css"

const Conditonal=({large, redColor}) => {
 return(
  <div className={[large && styles.large] + [redColor && styles.color]>
   ...
  </div>
 )
}

export default Conditonal

and if its just one conditonal statement with two class name, use this

import styles from "./styles.module.css"

const Conditonal=({redColor}) => {
 return(
  <div className={styles.large + [redColor && styles.color]>
   ...
  </div>
 )
}

export default Conditonal

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

I bind classNames to the css module imported to into the component.

import classNames from 'classnames'; 
import * as styles from './[STYLES PATH];
const cx = classNames.bind(styles); 

classnames gives the ability to declare className for a React element in a declarative way.

ex:

<div classNames={cx(styles.titleText)}> Lorem </div>

<div classNames={cx('float-left')}> Lorem </div> // global css declared without css modules
<div classNames={cx( (test === 0) ?
             styles.titleText : 
             styles.subTitleText)}>  Lorem </div> // conditionally assign classes

<div classNames={cx(styles.titleText, 'float-left')}> Lorem </div> //combine multiple classes

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to css

need to add a class to an element Using Lato fonts in my css (@font-face) Please help me convert this script to a simple image slider Why there is this "clear" class before footer? How to set width of mat-table column in angular? Center content vertically on Vuetify bootstrap 4 file input doesn't show the file name Bootstrap 4: responsive sidebar menu to top navbar Stylesheet not loaded because of MIME-type Force flex item to span full row width

Examples related to reactjs

Error: Node Sass version 5.0.0 is incompatible with ^4.0.0 TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type undefined raised when starting react app Template not provided using create-react-app How to resolve the error on 'react-native start' Element implicitly has an 'any' type because expression of type 'string' can't be used to index Invalid hook call. Hooks can only be called inside of the body of a function component How to style components using makeStyles and still have lifecycle methods in Material UI? React Hook "useState" is called in function "app" which is neither a React function component or a custom React Hook function How to fix missing dependency warning when using useEffect React Hook? Unable to load script.Make sure you are either running a Metro server or that your bundle 'index.android.bundle' is packaged correctly for release

Examples related to ecmascript-6

"Uncaught SyntaxError: Cannot use import statement outside a module" when importing ECMAScript 6 where is create-react-app webpack config and files? Can (a== 1 && a ==2 && a==3) ever evaluate to true? How do I fix "Expected to return a value at the end of arrow function" warning? Enums in Javascript with ES6 Home does not contain an export named Home How to scroll to an element? How to update nested state properties in React eslint: error Parsing error: The keyword 'const' is reserved Node.js ES6 classes with require