At my work, I had to add input which is quite similar to YouTube's "Start at" input for sharing video:
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:
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;
}
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:
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
:
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:
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 add0
to it - We don't want to show values like
00
(exception is seconds), so wefilter
-
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!
Top comments (10)
Nice 🙃
😁
Great code!
Thanks a lot!
Thank you 😊
Somehow my onBlur is getting triggered only when I click outside the the entire page, and not when I click outside input box. When I click outside input box, it's cursor is still blinking, it stays in focus, and onBlur doesn't work. Can you help about this?
That's so cool!
Thanks!
Good work 👏
Thank you 😊
thanks mate!