Reputation: 827
I've been musing on how best to conditionally apply a CSS class in React JS. I've seen some answers banding around but there aren't many out there or they're just not as elaborative as I'd like.
Upvotes: 33
Views: 91785
Reputation: 14112
I find this tiny (~220 Bytes) package extremely helpful to avoid writing a lot of boilerplate code: https://www.npmjs.com/package/clsx
You could simply write:
import clsx from 'clsx';
<section className={clsx('zb-card', <some dynamic optional classNames>)}>
or
<section className={clsx('foo', true && 'bar', 'baz')}>
//=> 'foo bar baz'
Upvotes: 0
Reputation: 396
Single Condition with Static ClassName
<div className={"container " + (this.props.condition === true ? 'show' : 'hidden')}>
Double Condition with Static ClassName
<div className={"container " + (this.props.condition === true ? 'show ' : 'hidden ') + (this.props.secondCondition === true ? 'visible' : 'invisible')}>
need to give space between conditional class or static class by the end
Upvotes: 0
Reputation: 638
Many answers assume this is about conditionally toggling CSS classes (ternary if is adequate), but this become far more obtuse when you need to optionally include classnames. Multiple ternary ifs with empty false expressions is verbose. An NPM package may be a tad much. A function too may be overkill for some.
Here's what I do.
const classNames = [
"className1",
condition1 && "className2",
condition2 && "className3",
condition3 && "className4",
].filter(e => e).join(" ");
Edit as of June 2021
I'm noticing this answer still sees the occasional upvote. Thought I'd provide a slightly updated example using a small and succinct arrow function:
const cls = (...classes) => classes.filter(Boolean).join(' ');
<div className={cls('mandatoryClass', condition && 'optionalClass')} />
Upvotes: 13
Reputation: 4484
You can simply condition class to state, like this:
<div className={ this.state.exampleIsTruthy ? 'yourClass' : '' }>
text
</div>
or if you want to switch classes based on a state like this:
<div className={ this.state.exampleTrueOrFalse ? 'shown' : 'hidden' }>
text
</div>
Upvotes: 42
Reputation: 1432
If you need to add a conditional class to an existing class, this one may give you an idea
<span className={'fa ' + (this.state.dropdownActive ? 'fa-angle-up' : 'fa-angle-down')}></span>
in this example, I am showing an arrow icon for a dropdown depending on the state of the dropdown. I need to keep the class fa
for any case to set the font-family of the span, and I only need to switch between fa-angle-up
and fa-angle-down
.
Same example with template literals
<span className={`fa ${this.state.dropdownActive ? 'fa-angle-up' : 'fa-angle-down'}`}></span>
Upvotes: 6
Reputation: 44900
The React documentation on manipulating class names suggests the classnames
NPM package.
The docs for the package are great.
The following snippet is straight from the package README
: Usage section
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: false, bar: true }); // => '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'
Upvotes: 23
Reputation: 1097
The solution which is stated below by other author in above comment works for me
<div className={ this.state.end ? 'hidden' : 'shown' }>text</div>
Just a add on if you want to add more classes then add class separated by space.
Upvotes: 4
Reputation: 2305
For the record I think the classnames
library answers are the most correct, but if you didn't want to pull in another dependency, you could roll your own simple implementation that works kind of like jQuery:
function getClassBuilder () {
return {
array: [],
add: function (className) {
if (this.array.indexOf(className) < 0) {
this.array.push(className);
}
},
remove: function (className) {
var index = this.array.indexOf(className);
if (index > -1) {
this.array.splice(index, 1);
}
},
toString: function () {
return this.array.join(' ');
}
}
}
then, when you need to use it:
var builder = getClassBuilder();
builder.add('class1');
builder.add('class2');
if (condition) { builder.remove('class1') };
<a href="#" className={builder.toString()}>Button</a>
Upvotes: 3
Reputation: 905
Use Classnames library https://github.com/JedWatson/classnames
The classNames function takes any number of arguments which can be a string or object. If the value of the key is falsy, it won't be included in the output.
var classNames = require('classnames');
var Button = React.createClass({
// ...
render () {
var btnClass = classNames({
'btn': true,
'btn-pressed': false,
'btn-over': true
});
// output: btnClass = "btn btn-over"
return <button className={btnClass}>{this.props.label}</button>;
}
});
Take a look at the doc and let me know if you have any questions!
Cheers
Upvotes: 4
Reputation: 827
Ok, so I've been experimenting and it turns out there are ways and it's not as hard as I thought. This might help those just starting out in React JS.
So there are two ways of doing so and two reasons for adding in-line styles:
(1) Add class name inside a style attribute as an object so it can be styled inside a regular CSS stylesheet, directly inside a JSX file or used for conditional CSS
EXAMPLE 1
const classNameAsAPlainObject = {
color: '#333333',
backgroundColor: '#999999'
}
<a href="#" className="an-existing-class" style={classNameAsAPlainObject} >
Button
</a>
EXAMPLE 2
const conditionIsSomething = {
color: 'red'
}
<a href="#" className="an-existing-class" style={conditionIsSomething ? 'classNameBasedOnCondition' : ' ' }>
Button
</a>
In the second example, two different classes can be declared depending on desired result or one class can be declared if condition is true or none if condition is false.
(2) Add it to the regular className attribute where a condition is required but be sure to accommodate for existing class names and be aware that this method requires styling in a regular CSS file. If no condition is required, then add the class as per normal to a className attribute.
EXAMPLE 3
<a href="#" className={"an-existing-class " + (conditionIsSomething ? 'thisClass' : 'thatClass')}>
Button
</a>
EXAMPLE 4
<a href="#" className={"an-existing-class " + (conditionIsSomething ? 'aClassIsAdded' : ' ')}>
Button
</a>
Again, if the condition requires it, one class can be declared or none as seen in example 4. Be sure to leave a space in either case after the "an-existing-class" and before the closing quote so there’s a space for the conditional class.
So I guess as a general rule of thumb, you're adding a class and styling as an object (as with Example 1 and 2), you can style it within the JSX file, but if adding a class name to the "className" attribute, you will be styling it inside a regular CSS file. I haven't experimented with this actually so I will give that a try. If anyone finds otherwise, please enlighten me.
Upvotes: -2