React time input⏳
Tags: react, timeinput, time, javascript
Published: 2020-11-22 16:31:34

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

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fm1do8httzc8n2o89oqr.png)

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](https://dev-to-uploads.s3.amazonaws.com/i/yffdx3fqdvihomong03f.gif)

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: 

```css
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;
}
```

```javascript
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")
);
```
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:

```javascript
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")
);
```

`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`:

```javascript
  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;
  };
```

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:
```javascript
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/, "");
};
```

- 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!