Responsive Numeric Keypad With HTML Javascript (Free Download)

Welcome to a tutorial on how to create an on-screen numeric keypad using only pure Javascript. Yes, HTML has gotten a lot more powerful and convenient these days. We can even define a field that only accepts numbers, but there is just one problem with it…

It will only display an on-screen keypad with mobile devices, and we cannot customize it. So here it is, this guide will walk you through a simple and lightweight custom numeric keypad – 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

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

If you spot a bug, feel free to comment below. I try to answer short 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.

 

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.

 

NUMERIC KEYPAD DEMO (HOW TO USE)

numpad.html
<!-- (A) LOAD JS + CSS -->
<!-- <link rel="stylesheet" href="numpad-light.css"/> -->
<link rel="stylesheet" href="numpad-dark.css"/>
<script src="numpad.js"></script>
 
<!-- (B) INPUT FIELDS -->
Field A: <input type="text" id="demoA"/>
Field B: <textarea id="demoB"></textarea>
 
<!-- (C) ATTACH NUMPAD -->
<script>
window.addEventListener("load", () => {
  // (C1) BASIC NUMPAD
  numpad.attach({target: document.getElementById("demoA")});
 
  // (C2) WITH ALL POSSIBLE OPTIONS
  numpad.attach({
    target: document.getElementById("demoB"),
    max: 10, // MAX 10 DIGITS
    decimal: false, // NO DECIMALS ALLOWED
    onselect : () => { // CALL THIS AFTER SELECTING NUMBER
      alert("DEMO B number set.");
    },
    oncancel : () => { // CALL THIS AFTER CANCELING
      alert("DEMO B canceled.");
    }
  });
});
</script>

Field A:

Field B:

For you guys who don’t want to read the entire tutorial and just want to use this as a “plugin”:

  1. Simply include the CSS and Javascript files in your own project.
  2. Define the <input> or <textarea> fields.
  3. On window load, use numpad.attach() attach the Numpad to the fields.

 

 

HOW IT WORKS

With that, let us now move into the details of how the Numpad works – This is for you guys who want to do some “deep customizations”.

 

PART 1) INITIALIZE NUMPAD (ATTACH HTML)

numpad.js
// (A) CREATE NUMPAD HTML
hwrap: null, // numpad wrapper container
hpad: null, // numpad itself
hdisplay: null, // number display
hbwrap: null, // buttons wrapper
hbuttons: {}, // individual buttons
init: () => {
  // (A1) WRAPPER
  numpad.hwrap = document.createElement("div");
  numpad.hwrap.id = "numWrap";
 
  // (A2) ENTIRE NUMPAD ITSELF
  numpad.hpad = document.createElement("div");
  numpad.hpad.id = "numPad";
  numpad.hwrap.appendChild(numpad.hpad);
 
  // (A3) DISPLAY
  numpad.hdisplay = document.createElement("input");
  numpad.hdisplay.id = "numDisplay";
  numpad.hdisplay.type = "text";
  numpad.hdisplay.disabled = true;
  numpad.hdisplay.value = "0";
  numpad.hpad.appendChild(numpad.hdisplay);
 
  // (A4) NUMBER BUTTONS
  numpad.hbwrap = document.createElement("div");
  numpad.hbwrap.id = "numBWrap";
  numpad.hpad.appendChild(numpad.hbwrap);

  // (A5) BUTTONS
  let buttonator = (txt, css, fn) => {
    let button = document.createElement("div");
    button.innerHTML = txt;
    button.classList.add(css);
    button.onclick = fn;
    numpad.hbwrap.appendChild(button);
    numpad.hbuttons[txt] = button;
  };
 
  // 7 TO 9
  for (let i=7; i<=9; i++) { buttonator(i, "num", () => { numpad.digit(i); }); }
  // BACKSPACE
  buttonator("&#10502;", "del", numpad.delete);
  // 4 TO 6
  for (let i=4; i<=6; i++) { buttonator(i, "num", () => { numpad.digit(i); }); }
  // CLEAR
  buttonator("C", "clr", numpad.reset);
  // 1 to 3
  for (let i=1; i<=3; i++) { buttonator(i, "num", () => { numpad.digit(i); }); }
  // CANCEL
  buttonator("&#10006;", "cx", () => { numpad.hide(1); });
  // 0
  buttonator(0, "zero", () => { numpad.digit(0); });
  // .
  buttonator(".", "dot", numpad.dot);
  // OK
  buttonator("&#10004;", "ok", numpad.select);
 
  // (A6) ATTACH NUMPAD TO HTML BODY
  document.body.appendChild(numpad.hwrap);
}
window.addEventListener("DOMContentLoaded", numpad.init);

numpad.init() is the first thing that gets called on page load, and all it does is to create the Numpad HTML. We will go through the layout below, but yes, there is only one copy of Numpad shared between all the input fields.

 

 

PART 2) BUTTON ACTIONS

numpad.js
// (B) BUTTON ACTIONS
// (B1) CURRENTLY SELECTED FIELD + MAX LIMIT
nowTarget: null, // Current selected input field
nowMax: 0, // Current max allowed digits
 
// (B2) NUMBER (0 TO 9)
digit: (num) => {
  let current = numpad.hdisplay.value;
  if (current.length < numpad.nowMax) {
    if (current=="0") { numpad.hdisplay.value = num; }
    else { numpad.hdisplay.value += num; }
  }
},
 
// (B3) ADD DECIMAL POINT
dot: () => {
  if (numpad.hdisplay.value.indexOf(".") == -1) {
    if (numpad.hdisplay.value=="0") { numpad.hdisplay.value = "0."; }
    else { numpad.hdisplay.value += "."; }
  }
},
 
// (B4) BACKSPACE
delete: () => {
  var length = numpad.hdisplay.value.length;
  if (length == 1) { numpad.hdisplay.value = 0; }
  else { numpad.hdisplay.value = numpad.hdisplay.value.substring(0, length - 1); }
},
 
// (B5) CLEAR ALL
reset: () => { numpad.hdisplay.value = "0"; },
 
// (B6) OK - SET VALUE
select: () => {
  numpad.nowTarget.value = numpad.hdisplay.value;
  numpad.hide();
  numpad.nowTarget.dispatchEvent(new Event("numpadok"));
}

Not going to explain line-by-line, but these should be pretty self-explanatory – Handle the button clicks.

 

 

PART 3) ATTACH NUMPAD

numpad.js
// (C) ATTACH NUMPAD TO INPUT FIELD
attach: (opt) => {
// OPTIONS
//  target: required, target field.
//  max: optional, maximum number of characters. Default 255.
//  decimal: optional, allow decimal? Default true.
//  onselect: optional, function to call after selecting number.
//  oncancel: optional, function to call after canceling.
 
  // (C1) DEFAULT OPTIONS
  if (opt.max === undefined) { opt.max = 255; }
  if (opt.decimal === undefined) { opt.decimal = true; }
 
  // (C2) GET + SET TARGET OPTIONS
  opt.target.readOnly = true; // PREVENT ONSCREEN KEYBOARD
  opt.target.dataset.max = opt.max;
  opt.target.dataset.decimal = opt.decimal;
  opt.target.addEventListener("click", () => { numpad.show(opt.target); });
 
  // (C3) ATTACH CUSTOM LISTENERS
  if (opt.onselect) {
    opt.target.addEventListener("numpadok", opt.onselect);
  }
  if (opt.oncancel) {
    opt.target.addEventListener("numpadcx", opt.oncancel);
  }
},
 
// (D) SHOW NUMPAD
show: (target) => {
  // (D1) SET CURRENT DISPLAY VALUE
  let cv = target.value;
  if (cv == "") { cv = "0"; }
  numpad.hdisplay.value = cv;
 
  // (D2) SET MAX ALLOWED CHARACTERS
  numpad.nowMax = target.dataset.max;
 
  // (D3) SET DECIMAL
  if (target.dataset.decimal == "true") {
    numpad.hbwrap.classList.remove("noDec");
  } else {
    numpad.hbwrap.classList.add("noDec");
  }
 
  // (D4) SET CURRENT TARGET
  numpad.nowTarget = target;
 
  // (D5) SHOW NUMPAD
  numpad.hwrap.classList.add("open");
},
 
// (E) HIDE NUMPAD
hide: (manual) => {
  if (manual) { numpad.nowTarget.dispatchEvent(new Event("numpadcx")); }
  numpad.hwrap.classList.remove("open");
}
  • (C) You already know this one, we use numpad.attach() to attach the Numpad. It simply sets the options as custom dataset.
  • Remember that there is only one shared HTML Numpad? To keep track of the currently selected input field:
    • (C2) Clicking on the input field will fire numpad.show().
    • (D4) The selected input field will be registered in the numbpad.nowTarget flag.
    • (D2 & D3) The maximum length and decimal options will also be read from the dataset and registered accordingly.
  • (D & E) To show the Numpad, we add an open CSS class to the HTML wrapper. So to close it, we simply remove open.

 

 

NUMPAD HTML

Wondering how the complete keypad looks like? Here we go:

<div id="numWrap">
  <div id="numPad" >
    <input id="numDisplay" type="text" disabled="">
    <div id="numBWrap" >
      <!-- FIRST ROW -->
      <div class="num">7</div> <div class="num">8</div> <div class="num">9</div> <div class="del">⤆</div>
 
      <!-- SECOND ROW -->
      <div class="num">4</div> <div class="num">5</div> <div class="num">6</div> <div class="clr">C</div>
 
      <!-- THIRD ROW -->
      <div class="num">1</div> <div class="num">2</div> <div class="num">3</div> <div class="cx">X</div>
 
      <!-- FORTH ROW -->
      <div class="zero">0</div> <div class="dot">.</div> <div class="ok">✔</div>
    <div>
  </div>
</div>

 

USEFUL BITS

That’s all for this guide, and here is a small section on some extras that may be useful to you.

 

THE SUMMARY

The Functions
Function Description
numpad.init() Runs when the window loads. Creates the necessary HTML for the keypad.
numpad.digit() Adds selected number digit to the current value.
numpad.dot() Adds a decimal point to the current value.
numpad.delete() “Backspace”, remove a digit from the current value.
numpad.reset() Reset the current value to 0.
numpad.select() Set the current value onto the attached input field.
numpad.attach() Attach the numpad onto a selected input field.
numpad.show() Show the numpad. Fired when an attached input field is clicked.
numpad.hide() Hide the numpad.
The Properties
Property Description
numpad.hwrap HTML Reference to the keypad wrapper container.
numpad.hpad The numpad itself.
numpad.hdisplay The numeric display.
numpad.hbwrap Buttons wrapper container.
numpad.hbuttons An object containing all the keypad buttons.
numpad.nowTarget Set by numpad.show(), the currently selected input field.
numpad.nowMax Set by numpad.show(), the current maximum character limit.
The Events
Event Description
numpadok On pressing the “OK” button.
numpadcx On pressing the “CANCEL” button.

 

 

CHANGE BUTTON LAYOUT OR ADD CUSTOM BUTTONS

  • To change the layout, simply reshuffle numpad.js section (A5).
  • If you don’t want 4 buttons per row, update CSS sections (D) and (E).

If you want buttons for funny characters like # - *, that will be a little more challenging.

  • Append a new function in section (B) to handle the button press. For example, hash : () => { ... }.
  • Then change section (A5) in the Javascript to add your “custom button”. For example, buttonator("#", "hash", numpad.hash).
  • Lastly, update the CSS button layout where applicable.

 

COMPATIBILITY CHECKS

Works well across all modern browsers.

 

THE END

Thank you for reading, and we have come to the end of this guide. I hope that it has helped you with your project, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

37 thoughts on “Responsive Numeric Keypad With HTML Javascript (Free Download)”

  1. Thanks a lot!
    How can I focus on the next input field of my form, after the value has been set with your numeric keyboard?

  2. Very tidy bit of code.
    After attaching my input box to “numpad”. Is is possible to detect that the value of the input box has change on the holding document, so that a script could run which will do some update process.

    Many thanks

    1. Sadly, onchange will only trigger on user input. So the hard way:

      1) Change (C) attach, add your own “after” option to accept a function.
      2) Change (B6) select. Call the function if “after” is set.

      1. Thank you W.S. TOH, was starting to come to the same conclusion.
        Have already added an option, to display a heading on the numpad.
        Thanks for your input.

  3. Great script! But I have one question.. I want to use this in a table, so have multiple rows with the same

    The numeric keypad only pop-up when clicking the first row. No on any other.
    Is there a way to change that?

    1. 1) Remove get element by ID during attach.

      attach: function(opt){
        // (C2) GET + SET TARGET OPTIONS
        // let target = document.getElementById(opt.target);
        target = opt.target;
      }

      2) Directly pass the elements in.

      var all = document.querySelectorAll("#TABLE input[type=text]");
      for (let i of all) { numpad.attach({ target: i }); }
      
    1. Sure.

      1) Modify show() – Attach an onkey listener when the keypad is open.
      2) If the key pressed is numeric, map it to digit().
      3) If the key pressed is dot, map it to dot().
      4) If the key pressed is backspace, map it to delete().
      5) If the key pressed is enter, map it to select().
      6) If the key pressed is esc, map it to hide().
      7) Modify hide() – Detach onkey listener when the keypad is closed.

      You decide if it is worth all the trouble.

    1. There are 2 places you need to modify:
      1) In the Javascript, function init() – Change the layout of the buttons under the (A5) BUTTONS section.
      2) In the CSS, change the width of the buttons under the (D) BUTTONS WRAPPER section.

      1. I changed the layout
        // First row – 1 to 3.
        for (var i = 1; i <= 3; i++) {
        append(i, numpad.digit);
        }
        // Second row – 4 to 6.
        for (var i = 4; i <= 6; i++) {
        append(i, numpad.digit);
        }
        // Third row – 7 to 9.
        for (var i = 7; i <= 9; i++) {
        append(i, numpad.digit);
        }
        // Last row – cancel, 0 , ok
        append("✖", numpad.reset, "cx");
        append(0, numpad.digit, "zero");
        numpad.zero = button;
        append("✔", numpad.select, "ok");

        and then the width: 25% , but there aren't changes, I still have 4 buttons per row.

Leave a Comment

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