Welcome to a tutorial on how to create a time picker using Javascript and CSS. Yes, there are plenty of time picker plugins available on the Internet. But some of them require a third-party library, and it simply does not make sense to load an entire library for just a single time picker. So here it is, a sharing of my simple time picker in vanilla Javascript plus CSS – Read on!
ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.
TABLE OF CONTENTS
DOWNLOAD & DEMO
Here is the link to download the script, and a short examples section on how to quickly use it in your own projects.
EXAMPLE CODE DOWNLOAD
Click here to download the source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
QUICKSTART – HOW TO USE
<!-- (A) LOAD THE CSS + JS -->
<link href="time-pick-dark.css" rel="stylesheet">
<!-- <link href="time-pick-light.css" rel="stylesheet"> -->
<script src="time-pick.js"></script>
<!-- (B) POPUP TIME PICKER -->
<h1>Popup Time Picker</h1>
<input type="text" id="demoA"/>
<!-- (C) INLINE TIME PICKER -->
<h1>Inline Time Picker</h1>
<input type="text" id="demoB1"/>
<div id="demoB2"></div>
<!-- (D) INIT -->
<script>
window.addEventListener("load", function(){
tp.attach({
target: "demoA"
});
tp.attach({
target: "demoB1",
wrap: "demoB2"
});
});
</script>
- A – Include the Javascript and CSS files on your own web page.
- B – If you want a popup time picker, simply define
<input type="text"/>
as usual. - C – If you want to show the time picker inline on the page:
- Define a
<input type="text"/>
field. - Also a
<div>
container for the time picker.
- Define a
- D – Finally, use the
tp.attach()
function on window load.
QUICK NOTES
If you spot a bug, please feel free to comment below. I try to answer questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.
TIME PICKER DEMO
Popup Time Picker
Inline Time Picker
HOW IT WORKS
With that, let us now move into more details on how the time picker works – This section is for the people who want “deep customizations” on the time picker.
THE JAVASCRIPT
var tp = {
// (A) CREATE TIME PICKER
instances : [], // All time picker instances
init: function (wrapper, target) {
// wrapper - container to generate time picker into
// target - optional, target input field for inline time pickers
// (A1) CREATE NEW INSTANCE + "GET ID"
let id = tp.instances.length;
tp.instances.push({ wrap : wrapper });
let inst = tp.instances[id];
if (target != undefined) { inst.target = target; }
// (A2) TIME PICKER ITSELF
let picker = document.createElement("div");
picker.className = "tp";
inst.wrap.appendChild(picker);
// (A3) *THE* BUTTONATOR - HR + MIN + AM/PM
let buttonator = function (segment) {
// Button Container
let box = document.createElement("div");
box.className = "tp-box";
// Up Button
let up = document.createElement("div");
up.innerHTML = "︿";
up.className = "tp-up";
// Current Value
let val = document.createElement("input");
val.type = "text";
val.disabled = true;
val.className = "tp-val";
if (segment == "hr") { val.value = "01"; }
else if (segment == "min") { val.value = "00"; }
else { val.value = "AM"; }
inst[segment] = val;
// Down Button
let down = document.createElement("div");
down.innerHTML = "﹀";
down.className = "tp-up";
// Button click handlers
if (segment == "ap") {
up.addEventListener("click", function(){
tp.sap(id);
});
down.addEventListener("click", function(){
tp.sap(id);
});
} else {
up.addEventListener("mousedown", function(){
tp.spin(id, segment, 1);
});
down.addEventListener("mousedown", function(){
tp.spin(id, segment, 0);
});
up.addEventListener("mouseup", tp.sspin);
up.addEventListener("mouseleave", tp.sspin);
down.addEventListener("mouseup", tp.sspin);
down.addEventListener("mouseleave", tp.sspin);
}
// Append all the buttons
box.appendChild(up);
box.appendChild(val);
box.appendChild(down);
picker.appendChild(box);
};
buttonator("hr");
buttonator("min");
buttonator("ap");
// (A4) OK BUTTON
let ok = document.createElement("input");
ok.type = "button";
ok.value = "OK";
ok.className = "tp-ok";
ok.addEventListener("click", function(){
tp.set(id);
});
picker.appendChild(ok);
},
// (B) "HOLD TO SPIN" FOR HOUR + MIN
stimer : null, // Spin timer
ssensitive : 100, // lower will spin faster
spin : function (id, segment, direction) {
if (tp.stimer == null) {
tp.sid = id;
tp.sseg = segment;
tp.smax = segment == "hr" ? 12 : 59;
tp.smin = segment == "hr" ? 1 : 0;
tp.sdir = direction;
tp.hmspin();
tp.stimer = setInterval(tp.hmspin, tp.ssensitive);
}
},
// (C) STOP HR/MIN SPIN
sspin : function () {
if (tp.stimer != null) {
clearInterval(tp.stimer);
tp.stimer = null;
}
},
// (D) SPIN HR OR MIN
sid : null, // Instance ID
sseg : null, // Segment to spin
smax : null, // Maximum value (12 for hr, 59 for min)
smin : null, // Minimum value (1 for hr, 0 for min)
sdir : null, // Spin direction
hmspin : function () {
// (D1) CURRENT VALUE
let box = tp.instances[tp.sid][tp.sseg],
cv = parseInt(box.value);
// (D2) SPIN!
if (tp.sdir) { cv++; }
else { cv--; }
if (cv < tp.smin) { cv = tp.smin; } if (cv > tp.smax) { cv = tp.smax; }
if (cv < 10) { cv = "0" + cv; }
// (D3) UPDATE DISPLAY
box.value = cv;
},
// (E) SPIN AM/PM
sap : function (id) {
// (E1) GET CURRENT VALUE
let box = tp.instances[id]["ap"],
cv = box.value;
// (E2) SET VALUE
box.value = (cv == "AM") ? "PM" : "AM";
},
// (F) SET SELECTED TIME
set : function (id) {
// (F1) GET + FORMAT HH:MM AM/PM
let inst = tp.instances[id],
timestamp = tp.instances[id]["hr"].value + ":" +
tp.instances[id]["min"].value + " " +
tp.instances[id]["ap"].value;
// (F2) SET TIMESTAMP
inst.target.value = timestamp;
// (F3) CLOSE TIME PICKER (POPUP ONLY)
if (id==0) {
inst.wrap.classList.remove("show");
}
},
// (G) ATTACH TIME PICKER TO TARGET
attach : function (opt) {
// target - input field
// wrap - optional, inline time picker
// (G1) SET INPUT FIELD READONLY
let target = document.getElementById(opt.target);
target.readOnly = true;
// (G2) INLINE VERSION - GENERATE TIME PICKER HTML
if (opt.wrap) {
tp.init(document.getElementById(opt.wrap), target);
}
// (G3) POPUP VERSION - SHOW POPUP ON CLICK
else {
target.addEventListener("click", function(){
// Get + set popup time
let cv = this.value;
if (cv == "") {
tp.instances[0].hr.value = "01";
tp.instances[0].min.value = "00";
tp.instances[0].ap.value = "AM";
} else {
tp.instances[0].hr.value = cv.substring(0, 2);
tp.instances[0].min.value = cv.substring(3, 5);
tp.instances[0].ap.value = cv.substring(6, 8);
}
// Set target + show popup
tp.instances[0].target = target;
tp.instances[0].wrap.classList.add("show");
});
}
}
};
// (H) CREATE "DEFAULT" POPUP TIME PICKER ON LOAD
window.addEventListener("DOMContentLoaded", function(){
let pop = document.createElement("div");
document.body.appendChild(pop);
pop.id = "tp-pop";
tp.init(pop);
});
JAVASCRIPT EXPLANATION
Yikes, this looks super confusing. Not going run through line-by-line, but here are the essentials.
- On window load (Section H) –
- We will create a “default popup time picker”
<div id="tp-pop">
and append it to the<body>
. - Use
init()
to generate the time picker HTML. - Yes, all popup instances will share that single
#tp-pop
.
- We will create a “default popup time picker”
- As you already know, we use
attach()
to tie an<input>
field to the time picker; For the inline time pickers, we will simply useinit()
again to generate the necessary HTML. - All generated time pickers will be stored in the
tp.instances
array. I.E.tp.instances[0]
is the popup, while all the following ones will be inline time pickers. - The rest of the functions are actually pretty much the “internal mechanics” –
spin() sspin() hmspin() sap()
are all helper functions that deal with setting the hour, minute, and AM/PM. - Finally,
set()
is fired when the user clicks on the “OK” button. This simply takes the time from the time picker and sets it onto the selected input field.
JAVASCRIPT SUMMARY
Property | Description |
tp.instances | All the generated time pickers. |
tp.stimer | Stores an interval timer for “hold to spin hour and minute”. |
tp.ssensitive | Spinner “sensitivity”, the interval time. Lower will spin faster. |
tp.sid | For the spinner. Currently selected time picker ID. |
tp.sseg | For the spinner. Currently selected time segment (hour or minute). |
tp.smax | For the spinner. Maximum allowed value. |
tp.smin | For the spinner. Minimum allowed value. |
tp.sdir | For the spinner. Spin direction – up or down. |
Function | Description |
tp.init() | Creates the HTML for the time picker. |
tp.spin() | Fired when mouse down on the hour or minute. |
tp.sspin() | Stop the spinner. |
tp.hmspin() | Calculate and update the hour/minute. |
tp.sap() | Toggle between AM/PM |
tp.set() | Set the current time onto the selected input field. |
tp.attach() | Attach a time picker to the selected field. |
TIME PICKER HTML
Here’s how the generated time picker HTML looks like:
<div class="tp">
<!-- HOUR -->
<div class="tp-box">
<div class="tp-up">︿</div>
<input type="text" disabled="" class="tp-val">
<div class="tp-up">﹀</div>
</div>
<!-- MINUTE -->
<div class="tp-box">
<div class="tp-up">︿</div>
<input type="text" disabled="" class="tp-val">
<div class="tp-up">﹀</div>
</div>
<!-- AM/PM -->
<div class="tp-box">
<div class="tp-up">︿</div>
<input type="text" disabled="" class="tp-val">
<div class="tp-up">﹀</div>
</div>
<!-- OK -->
<input type="button" value="OK" class="tp-ok">
</div>
CSS COSMETICS
With that, here are the cosmetics for the time picker.
/* (A) FOR THE POPUP TIME PICKER */
#tp-pop {
width: 100vw;
height: 100vh;
position: fixed;
top: 0; left: 0;
z-index: 999;
background: rgba(0, 0, 0, 0.7);
opacity: 0;
visibility: hidden;
transition: opacity 0.3s;
}
#tp-pop.show {
opacity: 1;
visibility: visible;
}
/* (B) TIME PICKER ITSELF */
.tp {
display: flex;
flex-wrap: wrap;
max-width: 320px;
background: #2d2d2d;
border: 1px solid #000;
}
.tp-box > *::selection {
background: transparent;
}
#tp-pop .tp {
margin: 50vh auto 0 auto;
transform: translateY(-50%);
}
/* (C) HR + MIN + AM/PM */
.tp-box {
width: 33%;
padding: 0 15px;
text-align: center;
box-sizing: border-box;
}
.tp-up, .tp-down {
font-size: 32px;
font-weight: bold;
color: #e01717;
padding: 10px 0;
cursor: pointer;
}
.tp-val {
box-sizing: border-box;
width: 100%;
background: #fff;
border: 0;
padding: 5px;
text-align: center;
font-size: 22px;
}
/* (D) OK BUTTON */
.tp-ok {
width: 100%;
background: #ce3535;
color: #fff;
border: 0;
padding: 15px 0;
margin: 10px;
cursor: pointer;
}
This should be straightforward, but just a quick reminder that #tp-pop
is the default “time picker popup”. We make it full screen, hide it by default, and use #tp-pop.show
to show it.
USEFUL BITS
That’s all for this project, and here is a small section on some extras that may be useful to you.
CHANGE TIME FORMAT
Don’t like the current time format?
- Change it in
set()
, sectionF1
. - Also, remember to change how it adapts existing values for popups in
attach()
, sectionG3
.
24 HOURS TIME FORMAT
This one is a little more challenging.
- Change the button layout in
init()
sectionA3
. Remove the AM/PM. - Update the spinner helper functions – Sections
B, D
. Allow the hour to spin from 0 to 23. - Lastly, update
set()
accordingly.
THE END
Thank you for reading, and we have come to the end of this guide. I hope that it has helped you to create a better website, and if you have anything to share with this guide, please feel free to comment below. Good luck and happy coding!