155

Using the css-in-js method to add classes to a react component, how do I add multiple components?

Here is the classes variable:

const styles = theme => ({
  container: {
    display: 'flex',
    flexWrap: 'wrap'
  },
  spacious: {
    padding: 10
  },
});

Here is how I used it:

return (<div className={ this.props.classes.container }>)

The above works, but is there a way to add both classes, without using the classNames npm package? Something like:

<div className={ this.props.classes.container + this.props.classes.spacious}>
Seth McClaine
  • 9,142
  • 6
  • 38
  • 64
Fatah
  • 2,184
  • 4
  • 18
  • 39

13 Answers13

291

you can use string interpolation:

<div className={`${this.props.classes.container} ${this.props.classes.spacious}`}>
Pardeep Jain
  • 84,110
  • 37
  • 165
  • 215
klugjo
  • 19,422
  • 8
  • 57
  • 75
79

You could use clsx. I noticed it used in the MUI buttons examples

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.container, classes.spacious)}>

Razzlero
  • 1,143
  • 8
  • 9
  • 6
    `clsx` package is smaller than `classnames`, so I prefer this solution – 0xh8h Apr 06 '20 at 10:33
  • 5
    clsx is included in Material UI, so its more preferred than classnames – DBrown Apr 29 '20 at 23:52
  • 2
    Per Wayne Bloss' comment below Mini's less-optimal answer: `@material-ui/core now depends on clsx, so if you don't want to increase your bundle size you'll want to use that instead`. So, +1 for this answer. – cssyphus Aug 06 '20 at 16:52
  • 2
    It seems `clsx` is not included in the latest `@mui/*` packages – loopmode Dec 01 '21 at 19:39
  • It's still a dependency, and referenced [in the MUI docs](https://mui.com/material-ui/getting-started/faq/#whats-the-clsx-dependency-for). I haven't installed it manually, but it works as expected. – Nick K9 Dec 21 '22 at 14:57
49

you can install this package

https://github.com/JedWatson/classnames

and then use it like this

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'

// lots of arguments of various types
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'

// other falsy values are just ignored
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
Mini
  • 1,138
  • 9
  • 24
  • 3
    This is the approach Material-UI uses in some of their examples, and works well so I'd recommend this. – Craig Myles Sep 05 '18 at 07:28
  • 2
    This should be the accepted answer. Works as expected – Howie Dec 27 '18 at 17:19
  • 2
    Been using this approach as well. Useful not just for having multiple classnames but also for making it conditional. – mouthzipper Feb 04 '19 at 10:32
  • 7
    `@material-ui/core` now depends on `clsx`, so if you don't want to increase your bundle size you'll want to use that instead - https://www.npmjs.com/package/clsx – Wayne Bloss Oct 04 '19 at 16:21
23

To have multiple classes applied to a component, wrap the classes you would like to apply within classNames.

For example, in your situation, your code should look like this,

import classNames from 'classnames';

const styles = theme => ({
  container: {
    display: "flex",
    flexWrap: "wrap"
  },
  spacious: {
    padding: 10
  }
});

<div className={classNames(classes.container, classes.spacious)} />

Make sure that you import classNames!!!

Have a look at material ui documentation where they use multiple classes in one component to create a customized button

Denis Tsoi
  • 9,428
  • 8
  • 37
  • 56
will92
  • 956
  • 7
  • 12
12

You can also use the extend property (the jss-extend plugin is enabled by default):

const styles = theme => ({
  container: {
    display: 'flex',
    flexWrap: 'wrap'
  },
  spaciousContainer: {
    extend: 'container',
    padding: 10
  },
});

// ...
<div className={ this.props.classes.spaciousContainer }>
VaclavSir
  • 595
  • 1
  • 4
  • 9
  • 2
    Unfortunately, not enabled by default anymore... vote to enable [here](https://github.com/mui-org/material-ui/issues/9342#) – egerardus Apr 25 '19 at 02:53
10

I think this will solve your problem:

const styles = theme => ({
 container: {
  display: 'flex',
  flexWrap: 'wrap'
},
 spacious: {
  padding: 10
},
});

and in react component:

<div className={`${classes.container} ${classes.spacious}`}>
Kalim M Vazir
  • 109
  • 1
  • 2
10

You can add multiple string classes and variable classes or props classes at same time in this way

className={`${classes.myClass}  ${this.props.classes.myClass2} MyStringClass`}

three classes at same time

Muhammad Muzamil
  • 1,013
  • 2
  • 18
  • 25
6

Yes, jss-composes provides you this:

const styles = theme => ({
 container: {
  display: 'flex',
  flexWrap: 'wrap'
},
 spacious: {
  composes: '$container',
  padding: 10
},
});

And then you just use classes.spacious.

Oleg Isonen
  • 1,463
  • 10
  • 10
  • while using multiple classname using compose ,it does not work. https://codesandbox.io/s/practical-cohen-l6qt5?file=/src/text.js – user970780 Jul 30 '20 at 08:25
3

classNames package can also be used as advanced as:

import classNames from 'classnames';

var arr = ['b', { c: true, d: false }];
classNames('a', arr); // => 'a b c'

let buttonType = 'primary';
classNames({ [`btn-${buttonType}`]: true }); // => 'btn-primary'
Hasan Sefa Ozalp
  • 6,353
  • 5
  • 34
  • 45
1

You can use this method below:

import clsx from 'clsx';
    
return <div className={clsx(classes.container, 'spacious')} />

This link helps.

adesurirey
  • 2,549
  • 2
  • 16
  • 36
0

You can apply two classes in material UI like that

import classNames from "classnames";
import { makeStyles } from "@material-ui/core/styles";

const useStyles = makeStyles({
  container: {
    display: 'flex',
    flexWrap: 'wrap',
  },
  spacious: {
    padding: 10,
  },
});

some code


 <div className={classNames(classes.container, classes.spacious)}>
      Try this one!
 </div>

How to add two classes using the comparison operator in Material UI.

If you want to use the comparison operator to define one or two classes, you need to apply


import classNames from "classnames";
import { makeStyles } from "@material-ui/core/styles";

const useStyles = makeStyles({
  maineButton: {
   borderRadius: "10px",
   minWidth: "80px",
   border: "1x solid #dcdcdc",
  },
  selectedButton: {
    border: "1x solid #3f51b5",
  },
});

some code

const [selected, setSelected] = useState(0);

some code

{data?.map((el, index) => (
   <ButtonBase 
     className={classNames(
        classes.maineButton, 
        index === selected && classes.selectedButton
        )}
     onClick{()=> setSelected(index)}
   >
     {el.text}
   </ButtonBase>
))}

if selected it will give you two classes

className={classNames(classes.maineButton, classes.selectedButton)}

if not, it will be only one

className={classNames(classes.maineButton)}
Ivan K.
  • 748
  • 7
  • 11
-1

If you want to assign multiple class names to your element, you can use arrays.

So in your code above, if this.props.classes resolves to something like ['container', 'spacious'], i.e. if

this.props.classes = ['container', 'spacious'];

you can simply assign it to div as

<div className = { this.props.classes.join(' ') }></div>

and result will be

<div class='container spacious'></div>
Praym
  • 2,038
  • 23
  • 21
-1

It can be done painlessly with descructuring, after all, these are JavaScript objects:

const truncate = {
  width: '100px',
  whiteSpace: 'nowrap',
  overflow: 'hidden',
  textOverflow: 'ellipsis',
};
email: {
    color: '#747474',
    ...truncate,
  },
yovchokalev
  • 623
  • 7
  • 14