<div style='text-align: center;'>
  <h1>Virtual Keyboard v.1.0.2</h1>
  <p>BETA <i>(Supported languages: english, russian)</i></p>
</div>
<hr/>

<table border='0' style='width: 100%;'>
  <tr>
    <td>
      <form class="form-horizontal" style='text-align: center;'>
      <div class="form-group">
        <label for="inputEmail3" class="control-label">Personal identification number:</label>
          <input data-virtual-element type="text" class="form-control" id="inputEmail3" placeholder="PIN">
      </div>
      <div class="form-group">
          <button class="btn btn-default">Login</button>
      </div>
    </form>
    </td>
    <td>
      <div id='tabular-virtual-keyboard'></div>
    </td>
  </tr>
</table>
#tabular-virtual-keyboard {
  min-width: 640px;
  box-shadow: 0 3px 6px rgba(51,51,51,0.16);
  display: table;
  padding: 0;
  margin: 0 auto;
  width: auto;
  color: #f1f1f1;
  background-color: #b7472a;
  border: 2px solid #b7472a;
  background: linear-gradient(to top, #b7472a 20px, #923922 56px);
  background: -webkit-linear-gradient(bottom, #b7472a 56px, #923922 20px);
  text-align: center;
}

#tabular-virtual-keyboard > .virtual-keyboard-row {
  display: table-row;  
  text-align: center;
}

#tabular-virtual-keyboard > .virtual-keyboard-row > .virtual-keyboard-column {
  display: table-cell;
  vertical-align: middle;
}


.virtual-keyboard-button {
  box-shadow: 0 2px 3px rgba(51,51,51,0.30);
  border: 2px solid #923922;
  font-size: 18px;
  color: #f1f1f1;
  background-color: #b7472a;
  background: linear-gradient(to top, #923922 20px, #b7472a 20px);
  background: -webkit-linear-gradient(bottom, #923922 20px, #b7472a 20px);
  cursor: pointer;
  padding: 0;
  display: inline-block;
  margin: 4px;
  outline: 0;
  text-decoration: none;
  border-radius: 4px;
  width: 48px;
  height: 48px;
  text-shadow: -1px 1px 1px #333;
  transition: all .1s ease-out;
}

.virtual-keyboard-button:hover {
  border: 2px solid #f1f1f1;
  box-shadow: 0px 0px 10px rgba(241,241,241,0.30);
}

.virtual-keyboard-button:active,
.virtual-keyboard-button:focus {
  background: #f1f1f1;
  color: #666;
  box-shadow: 0px 0px 10px rgba(241,241,241,0.30);
  text-shadow: 1px 0px 0px #333;
}
View Compiled
var VirtualKeyboard = {
  generate: function(target, matrix, language, uppercase = false) {
    var owner = this;
    
    for(var i = 0; i < matrix.length; i++) {
      var position = matrix[i];
      
      var vkr = document.createElement('div');
      vkr.setAttribute('class', 'virtual-keyboard-row');
      
      var vkc = document.createElement('div');
      vkc.setAttribute('class', 'virtual-keyboard-column');
      
      for (var j = 0; j < position.length; j++) {
        var button = document.createElement('button');
        
        switch(matrix[i][j]) {
          case '+backspace': 
            button.innerHTML = '<i class="fa fa-fw fa-long-arrow-left"></i>';
            button.setAttribute('data-trigger', 'backspace');
            button.setAttribute('title', 'Backspace');
            /* the slicing using timer */
            var mouseTimerHandler = null;
            button.addEventListener("mousedown", function(event) {

              mouseTimerHandler = setInterval(function(){
                if (event.which == 1) {
                  _lastElementFocused.value = _lastElementFocused.value.slice(0, -1);
                }
              }, 200);
            }, false);
            button.addEventListener("mouseup", function() {
              clearTimeout(mouseTimerHandler);
            });
            break;
          case '+international':
            button.innerHTML = '<i class="fa fa-fw fa-globe"></i>';
            button.setAttribute('data-trigger', 'international');
            button.setAttribute('title', 'International');
            break;
          case '+shift':
            button.innerHTML = '<i class="fa fa-fw fa-arrow-up"></i>';
            button.setAttribute('data-trigger', 'shift');
            button.setAttribute('title', 'Shift');
            break;
          case '+space':
            button.innerHTML = '&nbsp;';
            button.setAttribute('data-trigger', 'space');
            button.setAttribute('title', 'Space');
            button.style.width = '75%';
            break;
            
          default: 
            button.innerText = uppercase ? (matrix[i][j]).toUpperCase() : matrix[i][j]; 
            break;
        }
        
        button.setAttribute('class', 'virtual-keyboard-button');
        button.addEventListener('click', function () {
          _lastElementFocused.focus();
          var x = this.getAttribute('data-trigger');
          if (x != null) {
            switch(x) {
              case 'backspace':
                _lastElementFocused.value = _lastElementFocused.value.slice(0, -1);
                break;
              case 'international':
                var reversed = language === 'en'? 'ru' : 'en';
                target.innerHTML = '';
                owner.generate(target,owner.getMatrix(reversed), reversed);
                break;
              case 'space':
                _lastElementFocused.value = _lastElementFocused.value + ' ';
                break;
              case 'shift':
                var u = uppercase === true ? false : true;
                target.innerHTML = '';
                owner.generate(target,owner.getMatrix(language), language, u);
                break;
                    }
          }
          else {
            _lastElementFocused.value = _lastElementFocused.value + this.innerText;
          }
        });
        vkc.appendChild(button);

        vkr.appendChild(vkc);
        target.appendChild(vkr);
      }
    }
  },
  getMatrix: function(language) {
    var matrix = {en: [
      ['1','2','3','4','5','6','7','8','9','0','+backspace'],
      ['q','w','e','r','t','y','u','i','o','p','-'],
      ['a','s','d','f','g','h','j','k','l','+'],
      ['@','z','x','c','v','b','n','m','.','_'],
      ['+shift','+space','+international']
    ],
                  ru: [
                    ['1','2','3','4','5','6','7','8','9','0','+backspace'],
                    ['й','ц','у','к','е','н','г','ш','щ','з','х','ъ','-'],
                    ['ф','ы','в','а','п','р','о','л','д','ж','э','+'],
                    ['@','я','ч','с','м','и','т','ь','б','ю','ё','.','_'],
                    ['+shift','+space','+international']
                  ]};
    return matrix[language];
  },
  init: function(args) {
    if (args != undefined && args != null) {
      if (Object.keys(args).length > 0) {
        var owner = this;

        window._lastElementFocused = null;

        var target = document.getElementById(args['targetId']);
        var language = args['defaultLanguage'];
        var elements = document.querySelectorAll(args['inputSelector']);

        _lastElementFocused = elements[0];

        for (var i = 0; i < elements.length; i++) {
          elements[i].addEventListener('focus', function () {
            _lastElementFocused = this;
          });
        }
        owner.generate(target,owner.getMatrix(language), language);
      }
    }
  }
}

VirtualKeyboard.init({targetId: 'tabular-virtual-keyboard', defaultLanguage: 'en', inputSelector: '[data-virtual-element]'});

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css
  2. https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/js/bootstrap.min.js