Simple Time Picker In Pure Javascript CSS – Free Code Download

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 How It Works Useful Bits
The End

 

 

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

time-pick.html
<!-- (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.
  • 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

time-pick.js
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.
  • As you already know, we use attach() to tie an <input> field to the time picker; For the inline time pickers, we will simply use init() 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

The Properties
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.
The Functions
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.

time-pick-dark.css
/* (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(), section F1.
  • Also, remember to change how it adapts existing values for popups in attach(), section G3.

 

24 HOURS TIME FORMAT

This one is a little more challenging.

  • Change the button layout in init() section A3. 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!


Leave a Comment

Your email address will not be published. Required fields are marked *