React - Change Inline CSS Conditionally Based on Component State

freeCodeCampfreeCodeCamp
5 min read

If you're having trouble with freeCodeCamp's Change Inline CSS Conditionally Based on Component State challenge, you're probably not alone.

In this challenge, you need to add code to change some inline CSS conditionally based on the state of a React component.

When you first go to the challenge, here's the code you'll see:

class GateKeeper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: ''
    };
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    this.setState({ input: event.target.value })
  }
  render() {
    let inputStyle = {
      border: '1px solid black'
    };
    // change code below this line

    // change code above this line
    return (
      <div>
        <h3>Don't Type Too Much:</h3>
        <input
          type="text"
          style={inputStyle}
          value={this.state.input}
          onChange={this.handleChange} />
      </div>
    );
  }
};

Notice that an inline style object, inputStyle, has already been declared with some default styling.

Your goal in this challenge is to update inputStyle so the border of the input is 3px solid red when there are more than 15 characters in the input. Note that the text in the input box is saved in the component's state as input:

...
this.state = {
  input: ''
};
...

Close, but not quite

Imagine that, after reading the description and instructions, you come up with this:

class GateKeeper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: ''
    };
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    this.setState({ input: event.target.value })
  }
  render() {
    let inputStyle = {
      border: '1px solid black'
    };
    // change code below this line
    const char = 15;
    if(this.state.input > char) {
      inputStyle = {
        border:'3px solid red'
      }
    }  
    // change code above this line
    return (
      <div>
        <h3>Don't Type Too Much:</h3>
        <input
          type="text"
          style={inputStyle}
          value={this.state.input}
          onChange={this.handleChange} />
      </div>
    );
  }
};

But when you try to submit this, it doesn't pass all the tests. Let's take a closer look at what's going on.

Solutions

Using an if statement

Declaring char is fine, but take a closer look at the if condition:

if(this.state.input > char) {
  inputStyle = {
    border:'3px solid red'
  }
}

Remember that this.state.input is the value of the input box and is a string. For example, it could be "testing testing 1, 2, 3".

If you enter "testing testing 1, 2, 3" into the text box and lot this.state.input to the console:

class GateKeeper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: ''
    };
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    this.setState({ input: event.target.value })
  }
  render() {
    let inputStyle = {
      border: '1px solid black'
    };
    // change code below this line
    const char = 15;
    console.log(this.state.input);
    if(this.state.input > char) {
      inputStyle = {
        border:'3px solid red'
      }
    }  
    // change code above this line
    return (
      <div>
        <h3>Don't Type Too Much:</h3>
        <input
          type="text"
          style={inputStyle}
          value={this.state.input}
          onChange={this.handleChange} />
      </div>
    );
  }
};

You'll see testing testing 1, 2, 3 in the console.

Further, if you log this.state.input > char to the console, you'll see that it evaluates to false:

class GateKeeper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: ''
    };
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    this.setState({ input: event.target.value })
  }
  render() {
    let inputStyle = {
      border: '1px solid black'
    };
    // change code below this line
    const char = 15;
    console.log(this.state.input > char);
    if(this.state.input > char) {
      inputStyle = {
        border:'3px solid red'
      }
    }  
    // change code above this line
    return (
      <div>
        <h3>Don't Type Too Much:</h3>
        <input
          type="text"
          style={inputStyle}
          value={this.state.input}
          onChange={this.handleChange} />
      </div>
    );
  }
};

Simply put, you can't compare a string (this.state.input) directly to char, which is a number.

Instead, call the .length on this.state.input to get the length of the string and compare that to count:

class GateKeeper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: ''
    };
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    this.setState({ input: event.target.value })
  }
  render() {
    let inputStyle = {
      border: '1px solid black'
    };
    // change code below this line
    const char = 15;
    if(this.state.input.length > char) {
      inputStyle = {
        border:'3px solid red'
      }
    }  
    // change code above this line
    return (
      <div>
        <h3>Don't Type Too Much:</h3>
        <input
          type="text"
          style={inputStyle}
          value={this.state.input}
          onChange={this.handleChange} />
      </div>
    );
  }
};

Since the length of the string "testing testing 1, 2, 3" is 23 characters long (including spaces and commas), the border of the input box will turn red:

Image

Using a ternary operator

A ternary or conditional operator is like a one line if...else statement, and can help shorten your code significantly.

Go back to your solution and remove everything except the char variable:

class GateKeeper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: ''
    };
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    this.setState({ input: event.target.value })
  }
  render() {
    let inputStyle = {
      border: '1px solid black'
    };
    // change code below this line

    // change code above this line
    return (
      <div>
        <h3>Don't Type Too Much:</h3>
        <input
          type="text"
          style={inputStyle}
          value={this.state.input}
          onChange={this.handleChange} />
      </div>
    );
  }
};

Now take the condition you used in your earlier if statement and use it as the first part of the ternary condition: this.state.input.length > char ? : ;

Everything between ? and : indicates what happens if the earlier statement is true. You can just copy the code that was inside your if statement before: this.state.input.length > char ? inputStyle = { border:'3px solid red' } : ;

Now you need to handle the else portion of the ternary operator, which is everything between : and ;.

While you didn't use an else statement in your first solution, you effectively used inputStyle as-is. So just use inputStyle the way it's declared earlier in your code: this.state.input.length > char ? inputStyle = { border:'3px solid red' } : inputStyle;

Your whole solution should look like this:

class GateKeeper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: ''
    };
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    this.setState({ input: event.target.value })
  }
  render() {
    let inputStyle = {
      border: '1px solid black'
    };
    // change code below this line
    const char = 15;
    this.state.input.length > char ? inputStyle = { border:'3px solid red' } : inputStyle;
    // change code above this line
    return (
      <div>
        <h3>Don't Type Too Much:</h3>
        <input
          type="text"
          style={inputStyle}
          value={this.state.input}
          onChange={this.handleChange} />
      </div>
    );
  }
};

And that's it – you should be able to pass the challenge! Now go forth and conditionally style React components to your heart's content.

0
Subscribe to my newsletter

Read articles from freeCodeCamp directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

freeCodeCamp
freeCodeCamp

Learn to code. Build projects. Earn certifications—All for free.