DEV Community

Cover image for React time input⏳
Andriy Chemerynskiy
Andriy Chemerynskiy

Posted on

React time input⏳

At my work, I had to add input which is quite similar to YouTube's "Start at" input for sharing video:

Alt Text

I am a pro level programmer, so the first thing I did was googling. However, all inputs that I found were different from what I needed.

So I implemented my own clone of YouTube's "Start at" time input.


Before I jump into the implementation part, here is the demo of what we are going to archive:

Alt Text

Behind the scenes:

  • User types in
  • When he finishes typing and clicks somewhere else onBlur event is fired
  • Getting seconds from input value (getSecondsFromHHMMSS(value)
  • Converting those seconds back to hh:mm:ss format (toHHMMSS(seconds))

It may sound complicated now, but it will be clear a moment later 😉


So let's start coding.

Let's add a basic structure:

input {
  background-color: rgba(96, 108, 110, 0.15);
  height: 40px;
  padding: 10px 10px;
  color: #606c6e;
  font-size: 30px;
  outline: 0 solid transparent;
  border: 0 solid transparent;
  width: 100%;
  border-radius: 4px;
  letter-spacing: -0.4px;
  padding: 10px 18px;
  width: 200px;
}

body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 30px;
  text-align: center;
}
Enter fullscreen mode Exit fullscreen mode
const TimeInput = () => {
  const [value, setValue] = React.useState("0:00");

  const onChange = (event) => {
    setValue(event.target.value);
  };

  return (
    <input 
     type="text"
     onChange={onChange}
     value={value}
     />
  );
};

ReactDOM.render(<TimeInput />,
  document.getElementById("root")
);
Enter fullscreen mode Exit fullscreen mode

We created TimeInput component that has an initial value set to O:00 and we update the state on every change.

Now we will add onBlur handler:

const TimeInput = () => {
  const [value, setValue] = React.useState("0:00");

+  const onBlur = (event) => {
+    const value = event.target.value;
+    const seconds = Math.max(0, getSecondsFromHHMMSS(value));
+
+    const time = toHHMMSS(seconds);
+    setValue(time);
+  };

  ...

  return (
     <input
      type="text"
      onChange={onChange}
+     onBlur={onBlur}
      value={value}
     />
  );
};

ReactDOM.render(<TimeInput />,
  document.getElementById("root")
);
Enter fullscreen mode Exit fullscreen mode

onBlur function makes the same steps that I described earlier:

  • Getting seconds from input value (getSecondsFromHHMMSS(value)
  • Converting those seconds back to hh:mm:ss format (toHHMMSS(seconds))

Math.max(0, getSecondsFromHHMMSS(value)) returns 0 if seconds are negative, so we don't have wrong values in our input.

Now let's take a closer look at getSecondsFromHHMMSS:

  const getSecondsFromHHMMSS = (value) => {
    const [str1, str2, str3] = value.split(":");

    const val1 = Number(str1);
    const val2 = Number(str2);
    const val3 = Number(str3);

    if (!isNaN(val1) && isNaN(val2) && isNaN(val3)) {
    // seconds
      return val1;
    }

    if (!isNaN(val1) && !isNaN(val2) && isNaN(val3)) {
    // minutes * 60 + seconds
      return val1 * 60 + val2;
    }

    if (!isNaN(val1) && !isNaN(val2) && !isNaN(val3)) {
    // hours * 60 * 60 + minutes * 60 + seconds
      return val1 * 60 * 60 + val2 * 60 + val3;
    }

    return 0;
  };
Enter fullscreen mode Exit fullscreen mode

We split the input's value by ":". Then we grab 3 values from this array and convert them to numbers.

Depending on the context val1, val2, val3 represent different values and handle those cases:

  • Only seconds (eg. 10, 40, 70 etc.)
  • Minutes and seconds (eg. 1:20, 0:10, 14:40 etc.)
  • Hours, minutes, and seconds (eg. 1:12:40, 123:49:12 etc.)

Finally, we format seconds from getSecondsFromHHMMSS back to hh:mm:ss format:

const toHHMMSS = (secs) => {
    const secNum = parseInt(secs.toString(), 10);
    const hours = Math.floor(secNum / 3600);
    const minutes = Math.floor(secNum / 60) % 60;
    const seconds = secNum % 60;

    return [hours, minutes, seconds]
      .map((val) => (val < 10 ? `0${val}` : val))
      .filter((val, index) => val !== "00" || index > 0)
      .join(":")
      .replace(/^0/, "");
};
Enter fullscreen mode Exit fullscreen mode
  • We get hours, minutes, seconds from total seconds using simple math
  • map those values and if the value is less than 10 we add 0 to it
  • We don't want to show values like 00 (exception is seconds), so we filter
  • join our strings with ":"
  • replace leading zero

And it's working 😎

Codepen: https://codepen.io/andrewchmr-the-vuer/pen/wvWLRVw


I hope this article was helpful and saved you the time of thinking about how to do this 😉

Thanks for reading!

Discussion (8)

Collapse
isarisariver profile image
Marian

I am a pro level programmer, so the first thing I did was googling

Nice 🙃

Collapse
andrewchmr profile image
Andriy Chemerynskiy Author

😁

Collapse
rubenvillarnet profile image
Rubén Villar Grela

Great code!

Thanks a lot!

Collapse
andrewchmr profile image
Andriy Chemerynskiy Author

Thank you 😊

Collapse
lesmiks profile image
Oles

That's so cool!

Collapse
andrewchmr profile image
Andriy Chemerynskiy Author

Thanks!

Collapse
kplc_caxapok profile image
крістінич

Good work 👏

Collapse
andrewchmr profile image
Andriy Chemerynskiy Author

Thank you 😊