Reputation: 7742
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?
Upvotes: 283
Views: 429979
Reputation: 3791
The issue at hand I believe is whether a trailing space in the class name is HTML 5 complaint. The answer is yes.
When specified on HTML elements, the class attribute must have a value that is a set of space-separated tokens representing the various classes
https://html.spec.whatwg.org/multipage/dom.html#classes
A string containing a set of space-separated tokens may have leading or trailing ASCII whitespace.
https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#set-of-space-separated-tokens
With that settled, the obvious solution is to use a template literal as already mentioned.
<div className={`classOne classTwo ${stringOfMoreClasses || ''}`}>
If stringOfMoreClasses
is nill, the className
attribute will just include the original two classes with a single trailing white space.
Remember React re-runs the component function a lot! This is not a place where you want anything process heavy.
Upvotes: 0
Reputation: 21486
Someone mentioned the classnames library, which looks interesting and useful, but you could do the same thing yourself:
…
// keep your class names in an object,
// enabled or disabled by the Boolean value
const classNames = {
MyComponent: true
foo: false
bar: someConditionVar
};
// construct the class name, e.g. "MyComponent bar"
const className = Object.keys(classNames).filter(className =>
classNames[className]).join(' ');
// example usage in React JSX
return (
<div className="{className} …
Iterating through the object name/value entries rather than only the keys allows this to be shortened to a single statement:
…
const className = Object.entries({
MyComponent: true
foo: false
bar: someConditionVar
}).filter(entry => entry[1]).map(entry => entry[0]).join(' ');
// example usage in React JSX
return (
<div className="{className} …
Upvotes: 0
Reputation: 364
Simply combine class names within an array, remove empty values and join into the string.
<div className={["wrapper", "searchDiv",, undefined, null, this.state.something].filter((e) => e).join(" ")}"}>
...
</div>
Result is the className without extra spaces.
Have a creative day!
Upvotes: 0
Reputation: 318
A word of caution to those that are using back ticks or concatenation for className in React: You need to have spaces between your class names. Without them, you have a long word that doesn't match any of your css.
Upvotes: 0
Reputation: 388
[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 : ""}`}>
Upvotes: 12
Reputation: 514
Don't think of a solution so complicated.
here is the easiest solution for your problem.
<div className={`wrapper searchDiv ${this.state.something}`}>
...
</div>
Upvotes: 14
Reputation: 11
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.
Upvotes: 0
Reputation: 863
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>
)
Upvotes: 3
Reputation:
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"
Upvotes: 0
Reputation: 674
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
}));
}
Upvotes: 8
Reputation: 29
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';
Upvotes: 1
Reputation: 11369
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.
Upvotes: 421
Reputation: 1133
getBadgeClasses() {
let classes = "badge m-2 ";
classes += (this.state.count === 0) ? "badge-warning" : "badge-primary";
return classes;
}
<span className={this.getBadgeClasses()}>Total Count</span>
Upvotes: 2
Reputation: 1075
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" : "")'}>
Upvotes: 8
Reputation: 1177
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"
}
Upvotes: 52
Reputation: 900
A simple possible syntax will be:
<div className={`wrapper searchDiv ${this.state.something}`}>
Upvotes: 53
Reputation: 302
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})} />
Upvotes: 3
Reputation: 2605
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.
Upvotes: 81