Why is this input type=time invalid in some browsers with a “stepMismatch”: true?

I have a very simple input type=time with a valid time value according to MDN:

:invalid { border-color: red; }
<input type="time" value="00:00:00.750" onchange="console.log(this.validity)" />

If I just run the snippet (Safari) and edit the value (Firefox 93), whatever I edit it to, the input is considered invalid afterwards, with a "stepMismatch": true validity fail reason (Safari 15, Firefox 93 and 94, MacOS 12).

What’s going on here? How is step even working for this input type, and how to get rid of the invalid state?

Answer

According to MDN, the default step attribute of an input[type=time] is equal to 60, measured in seconds.

This means that in the absence of an explicit step attribute, the time can only be changed in multiples of one minute.

The step works with the min attribute if present, or the value attribute otherwise, so setting an initial value="00:00:00.750" means that only values that are 750ms past a given minute are considered valid, and depending on the browser and how it displays the input, this may not even be possible for the user to do.

Setting step="1" will give you the option to set the seconds part of the time as you wish, and step="0.001" should also let you set milliseconds. step="any" is also an option, but at this time it’s not clearly defined. I personally would take it to mean it basically disables the resolution check entirely, but browsers may disagree.