davidhtien
davidhtien

Reputation: 2618

Correct way to handle conditional styling in React

I'm doing some React right now and I was wondering if there is a "correct" way to do conditional styling. In the tutorial they use

style={{
  textDecoration: completed ? 'line-through' : 'none'
}}

I prefer not to use inline styling so I want to instead use a class to control conditional styling. How would one approach this in the React way of thinking? Or should I just use this inline styling way?

Upvotes: 237

Views: 436681

Answers (17)

Kolade Chris
Kolade Chris

Reputation: 195

This is one way I got it done in a small React Bootstrap project:

<Badge bg={`${todo.completed === true ? 'success' : 'danger'}`}>
  {todo.completed === true ? 'Completed' : 'Not Completed'}
</Badge>

Of course success and danger can be any color since they're bootstrap colors.

Upvotes: 0

CbeDroid1614
CbeDroid1614

Reputation: 111

If you do not want to overwrite the original style, you can use empty styling with {}.

For instance, assigning a background-color, when you need to keep the initial color if the condition is not met.

style={ onError ? {backgroundColor: 'red'} : {} }
// Will not overwrite the background color if the error does not occur.
style={ completed ? {textDecoration: 'line-through'} : {} }

Upvotes: 7

Ronak Solanki
Ronak Solanki

Reputation: 111

Sorted way to apply inline styling on some condition.

style={areFieldsDisabled ? {opacity: 0.5} : '' }

Upvotes: 5

Bhavesh Sharma
Bhavesh Sharma

Reputation: 161

Change Inline CSS Conditionally Based on Component State.

This is also the Correct way to handle conditional styling in React.

condition ? expressionIfTrue : expressionIfFalse;

example =>

{this.state.input.length > 15 ? inputStyle={border: '3px solid red'}: inputStyle }

This code means that if the character is more than 15 entered in the input field, then our input field's border will be red and the length of the border will be 3px.

Upvotes: 0

Denis S Dujota
Denis S Dujota

Reputation: 611

I came across this question while trying to answer the same question. McCrohan's approach with the classes array & join is solid.

Through my experience, I have been working with a lot of legacy ruby code that is being converted to React and as we build the component(s) up I find myself reaching out for both existing css classes and inline styles.

example snippet inside a component:

// if failed, progress bar is red, otherwise green 
<div
    className={`progress-bar ${failed ? 'failed' : ''}`}
    style={{ width: this.getPercentage() }} 
/>

Again, I find myself reaching out to legacy css code, "packaging" it with the component and moving on.

So, I really feel that it is a bit in the air as to what is "best" as that label will vary greatly depending on your project.

Upvotes: 3

Zahra Mirzaei
Zahra Mirzaei

Reputation: 759

If you want assign styles based on condition, its better you use a class name for styles. For this assignment, there are different ways. These are two of them.

1.

    <div className={`another-class ${condition ? 'active' : ''}`} />
    <div className={`another-class ${condition && 'active'}`} />

Upvotes: 4

Fotios Tsakiris
Fotios Tsakiris

Reputation: 1556

In case someone uses Typescript (which does not except null values for style) and wants to use react styling, I would suggest this hack:

<p 
style={choiceStyle ? styles.choiceIsMade : styles.none}>
{question}
</p>

const styles = {
choiceIsMade: {...},
 none: {}
}

Upvotes: 0

Hrishikesh Baidya
Hrishikesh Baidya

Reputation: 567

 style={{
              whiteSpace: "unset",
              wordBreak: "break-all",
              backgroundColor: one.read == false && "#e1f4f3",
              borderBottom:'0.8px solid #fefefe'
            }}

Upvotes: 3

Aayush Bhattacharya
Aayush Bhattacharya

Reputation: 1934

inline style handling

style={{backgroundColor: selected ? 'red':'green'}}

using Css

in js

className={`section ${selected && 'section_selected'}`}

in css

.section {
  display: flex;
  align-items: center;
} 
.section_selected{
  background-color: whitesmoke;
  border-width: 3px !important;
}

same can be done with Js stylesheets

Upvotes: 17

Rajitha Fernando
Rajitha Fernando

Reputation: 1865

You can use somthing like this.

render () {
    var btnClass = 'btn';
    if (this.state.isPressed) btnClass += ' btn-pressed';
    else if (this.state.isHovered) btnClass += ' btn-over';
    return <button className={btnClass}>{this.props.label}</button>;
  }

Or else, you can use classnames NPM package to make dynamic and conditional className props simpler to work with (especially more so than conditional string manipulation).

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'

Upvotes: 0

Snivio
Snivio

Reputation: 1864

The best way to handle styling is by using classes with set of css properties.

example:

<Component className={this.getColor()} />

getColor() {
    let class = "badge m2";
    class += this.state.count===0 ? "warning" : danger;
    return class;
}

Upvotes: 0

diegocl02
diegocl02

Reputation: 3238

Another way, using inline style and the spread operator

style={{
  ...completed ? { textDecoration: completed } : {}
}}

That way be useful in some situations where you want to add a bunch of properties at the same time base on the condition.

Upvotes: 18

Vlado
Vlado

Reputation: 3777

If you need to conditionally apply inline styles (apply all or nothing) then this notation also works:

style={ someCondition ? { textAlign:'center', paddingTop: '50%'} : {}}

In case 'someCondition' not fulfilled then you pass empty object.

Upvotes: 125

hawkEye
hawkEye

Reputation: 361

instead of this:

style={{
  textDecoration: completed ? 'line-through' : 'none'
}}

you could try the following using short circuiting:

style={{
  textDecoration: completed && 'line-through'
}}

https://codeburst.io/javascript-short-circuit-conditionals-bbc13ac3e9eb

key bit of information from the link:

Short circuiting means that in JavaScript when we are evaluating an AND expression (&&), if the first operand is false, JavaScript will short-circuit and not even look at the second operand.

It's worth noting that this would return false if the first operand is false, so might have to consider how this would affect your style.

The other solutions might be more best practice, but thought it would be worth sharing.

Upvotes: 21

David L. Walsh
David L. Walsh

Reputation: 24815

If you prefer to use a class name, by all means use a class name.

className={completed ? 'text-strike' : null}

You may also find the classnames package helpful. With it, your code would look like this:

className={classNames({ 'text-strike': completed })}

There's no "correct" way to do conditional styling. Do whatever works best for you. For myself, I prefer to avoid inline styling and use classes in the manner just described.

POSTSCRIPT [06-AUG-2019]

Whilst it remains true that React is unopinionated about styling, these days I would recommend a CSS-in-JS solution; namely styled components or emotion. If you're new to React, stick to CSS classes or inline styles to begin with. But once you're comfortable with React I recommend adopting one of these libraries. I use them in every project.

Upvotes: 146

Abhay Shiro
Abhay Shiro

Reputation: 3627

 <div style={{ visibility: this.state.driverDetails.firstName != undefined? 'visible': 'hidden'}}></div>

Checkout the above code. That will do the trick.

Upvotes: 203

S McCrohan
S McCrohan

Reputation: 6693

First, I agree with you as a matter of style - I would also (and do also) conditionally apply classes rather than inline styles. But you can use the same technique:

<div className={{completed ? "completed" : ""}}></div>

For more complex sets of state, accumulate an array of classes and apply them:

var classes = [];

if (completed) classes.push("completed");
if (foo) classes.push("foo");
if (someComplicatedCondition) classes.push("bar");

return <div className={{classes.join(" ")}}></div>;

Upvotes: 8

Related Questions