227

I need to add a dynamic class to a list of regular classes, but have no idea how (I'm using babel), something like this:

<div className="wrapper searchDiv {this.state.something}">
...
</div>

Any ideas?

Flip
  • 5,443
  • 6
  • 39
  • 69
Mankind1023
  • 6,169
  • 13
  • 53
  • 73
  • Useful answers for reactjs styling best practice at [link](https://stackoverflow.com/questions/26882177/react-js-inline-style-best-practices/31638988#31638988) – Rahil Ahmad Jan 16 '18 at 04:03

14 Answers14

341

You can either do this, normal JavaScript:

className={'wrapper searchDiv ' + this.state.something}

or the string template version, with backticks:

className={`wrapper searchDiv ${this.state.something}`}

Both types are of course just JavaScript, but the first pattern is the traditional kind.

Anyway, in JSX, anything enclosed in curly brackets is executed as JavaScript, so you can basically do whatever you want there. But combining JSX strings and curly brackets is a no-go for attributes.

daaawx
  • 2,798
  • 2
  • 14
  • 15
dannyjolie
  • 10,081
  • 3
  • 30
  • 28
  • and what in case of multiple classes ? – Pardeep Jain Oct 04 '17 at 11:29
  • 8
    In the case of multiple dynamic classes, all dynamic classes must be coming from the state, i.e. it is not possible to use `element.classList.add("my-class")`; therefore allowing for:`className={\`wrapper searchDiv ${this.state.something ? "my-class " : ""} ${this.state.somethingElse ? "my-other-class " : ""}\`}` – Kevin Farrugia Apr 25 '18 at 13:18
  • `className={'wrapper searchDiv} + this.state.isTrue ? 'my-class' : ' '` This doesn't work. Can anybody tell why? – kryptokinght Dec 02 '18 at 18:28
  • @kryptokinght You can try `className={'wrapper searchDiv ' + (this.state.isTrue ? 'my-class' : ' ')}` – Sumit Patil Nov 26 '20 at 13:10
69

Depending on how many dynamic classes you need to add as your project grows it's probably worth checking out the classnames utility by JedWatson on GitHub. It allows you to represent your conditional classes as an object and returns those that evaluate to true.

So as an example from its React documentation:

render () {

var btnClass = classNames({
  'btn': true,
  'btn-pressed': this.state.isPressed,
  'btn-over': !this.state.isPressed && this.state.isHovered
});

return <button className={btnClass}>I'm a button!</button>;

} 

Since React triggers a re-render when there is a state change, your dynamic class names are handled naturally and kept up to date with the state of your component.

Brad Colthurst
  • 2,425
  • 13
  • 13
  • 7
    The use of classNames for such a simple thing is an overkill. Avoid using it and opt for the simple answer of dannyjolie – checklist Nov 02 '17 at 20:15
  • 4
    Are you sure it's a simple thing? Near always you want to have fine grained full control over what classes are applied to elements. – Dragas Jun 26 '18 at 12:03
  • 6
    @checklist I would argue otherwise, the classnames package is 1.1kB before Gzipping (and half a kB after Gzipping), has no dependencies, and provides a much cleaner API for class name manipulation. There's no need to prematurely optimise something so small, when the API is much more expressive. When using standard string manipulation you have to remember to account for spacing, either before every conditional class name, or after every standard class name. – tomhughes Jul 06 '18 at 08:39
  • classNames is great, I found that reading, adding, and fixing props were easier than manual manipulation as the component grew in complexity. – MiFiHiBye Dec 15 '18 at 00:51
48

A simple possible syntax will be:

<div className={`wrapper searchDiv ${this.state.something}`}>
oligopol
  • 760
  • 10
  • 15
45

Here is the Best Option for Dynamic className , just do some concatenation like we do in Javascript.

     className={
        "badge " +
        (this.state.value ? "badge-primary " : "badge-danger ") +
        " m-4"
      }
Saad Mirza
  • 1,014
  • 12
  • 21
13

Don't think of a solution so complicated.

here is the easiest solution for your problem.

<div className={`wrapper searchDiv ${this.state.something}`}>
   ...
</div>
rahul.taicho
  • 1,301
  • 1
  • 8
  • 18
Daniel Paul
  • 467
  • 1
  • 5
  • 12
8

try this using hooks:

const [dynamicClasses, setDynamicClasses] = React.useState([
    "dynamicClass1", "dynamicClass2"
]);

and add this in className attribute :

<div className=`wrapper searchDiv ${[...dynamicClasses]}`>
...
</div>

to add class :

    const addClass = newClass => {
       setDynamicClasses([...dynamicClasses, newClass])
    }

to delete class :

        const deleteClass= classToDelete => {

           setDynamicClasses(dynamicClasses.filter(class = > {
             class !== classToDelete
           }));

        }
Penny Liu
  • 11,885
  • 5
  • 66
  • 81
Hamza Khattabi
  • 442
  • 4
  • 9
  • the `...` spread operator would actually join the string by a `,` comma by default. e.g. `wrapper searchDiv ${[...'c','as']}` => `"wrapper searchDiv c,as"` – Gianfranco P. Aug 31 '21 at 12:52
7

If you need style names which should appear according to the state condition, I prefer to use this construction:

<div className={'wrapper searchDiv' + (this.state.something === "a" ? " anotherClass" : "")'}>
Sergey
  • 915
  • 3
  • 12
  • 31
3

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', ['class3', 'class4'], { 
    class5 : function() { return false; },
    class6 : function() { return true; }
});

<div className={getClassNames({class1: true, class2 : false})} />
Tushar Sharma
  • 182
  • 15
3

If you're using css modules this is what worked for me.

const [condition, setCondition] = useState(false);

\\ toggle condition

return (
  <span className={`${styles.always} ${(condition ? styles.sometimes : '')`}>
  </span>
)
quarterpi
  • 743
  • 1
  • 5
  • 13
2
getBadgeClasses() {
    let classes = "badge m-2 ";
    classes += (this.state.count === 0) ? "badge-warning" : "badge-primary";
    return classes;
}

<span className={this.getBadgeClasses()}>Total Count</span>
1
className={css(styles.mainDiv, 'subContainer')}

This solution is tried and tested in React SPFx.

Also add import statement :

import { css } from 'office-ui-fabric-react/lib/Utilities';
Maximouse
  • 3,550
  • 1
  • 13
  • 25
Harjot Singh
  • 29
  • 1
  • 3
0
const ClassToggleFC= () =>{
  
  const [isClass, setClass] = useState(false);

  const toggle =() => {
       setClass( prevState => !prevState)
  }
  
  return(
      <>
        <h1 className={ isClass ? "heading" : ""}> Hiii There </h1>
       <button onClick={toggle}>Toggle</button>
      </>
   )

}

I simply created a Function Component. Inside I take a state and set initial value is false..

I have a button for toggling state..

Whenever we change state rerender component and if state value (isClass) is false h1's className should be "" and if state value (isClass) is true h1's className is "heading"

  • Hi, can you please explain with a few words how/why your solution works. While for experts "the truth may be in the code", for many visitors a few helpful words are worth alot. Thanks! – Robert Feb 09 '21 at 19:39
0

Even though all of the answers above are quite good, the one that caught my attention is the string interpolation solution. So I'd like to propose a different approach to that using a custom StringBuilder.

Here's the implementation.

class StringBuilder {
  static Builder() {
    class Builder {
      constructor() {
        this.bucket = [];
      }

      append(str) {
        if (str !== null) {
          this.bucket.push(str);
        }
        return this;
      }

      build() {
        return this.bucket.join(' ');
      }
    }
    return new Builder();
  }
}

Then you would just use it like this within a component.

const Field = (props) => {
  const { label } = props;

  const [hasFocus, setFocus] = useState(false);

  const labelClasses = new StringBuilder.Builder()
    .append('form-control')
    .append(hasFocus ? 'has-focus' : null)
    .build();

  const turnOnFocus = () => setFocus(true);
  const turnOffFocus = () => setFocus(false);

  return (
    <div onClick={turnOnFocus} onBlur={turnOffFocus} className="form-group">
      <input
        type="text"
        defaultValue=""
        onChange={setValue}
      />
      <label className={labelClasses}>{label}</label>
    </div>
  );
};

In general, if you have more elements that require dynamic CSS classes, you could just instantiate another builder for that particular element. Additionally, if the class appears in more than one element with the same logic, then the solution would be extracting that logic to a method or function.

Alvaro
  • 11
  • 2
0

[UPDATED Apr-21 2022: Adding curly brackets before and after backticks to prevent error]

you can simply use the condition for applying the specific class you want

<div className={`wrapper searchDiv ${this.state.something ? "class that you want" : ""}`}>

if you want to use the class of makeStyle you can use it like

<div className={`wrapper searchDiv ${this.state.something ? classes.specifiedClass : ""}`}>

Dika
  • 1,962
  • 4
  • 30
  • 44
Ihtisham Tanveer
  • 150
  • 2
  • 12