React: validation on controllable input is not consistent

Viewed 27

I've 2 controllable text input with validation:

  • required={true}
  • minLength={5}
  • maxLength={10}

Both are share the same state, so their text are always in sync.

value={text}
onChange={(e) => setText(e.target.value)}

The initial value of them are 'ab':

const [text, setText] = useState("ab");

Then I added a css for visualizing the validation state:

input[type="text"]:valid {
  background-color: lightgreen !important;
}
input[type="text"]:invalid {
  background-color: pink !important;
}

The problem:

  1. At the first load, both color are green.
    The value are 'ab' it doesn't satisfy the validation.
    Why not colored red?
  2. When i added one character of the first textbox => abc
    The color is red, that's to be expected. But the second one still colored green. That's not expected.

Anyone can fix the problem? I want the text & validation are in sync.

enter image description here

Sandbox: enter link description here

code:

import "./styles.css";
import { useState } from "react";
import "./App.css";

export default function App() {
  const [text, setText] = useState("ab");

  return (
    <div className="App">
      <input
        type="text"
        required={true}
        minLength={5}
        maxLength={10}
        value={text}
        onChange={(e) => setText(e.target.value)}
      />
      <br />
      <input
        type="text"
        required={true}
        minLength={5}
        maxLength={10}
        value={text}
        onChange={(e) => setText(e.target.value)}
      />
    </div>
  );
}

css:

input[type="text"]:valid {
  background-color: lightgreen !important;
}
input[type="text"]:invalid {
  background-color: pink !important;
}
1 Answers

To be completely honest, I don't know why React is behaving this way, but an alternative would be to add a 'valid' or 'invalid' class to the input depending on the 'text' value:

<input
  className={text.length >= 5 && text.length <= 10 ? 'valid' : 'invalid'}
  type="text"
  required={true}
  value={text}
  onChange={(e) => setText(e.target.value)}
/>
.valid {
  background-color: lightgreen !important;
}
.invalid {
  background-color: pink !important;
}
Related