Build a Virtual Keyboard using HTML CSS & JavaScript
Last Updated :
31 Jul, 2024
Improve
In this article, we will build a virtual keyboard using HTML, CSS, and JavaScript. A virtual keyboard is a user interface component that allows users to input text by clicking on the keys displayed on the screen. Our keyboard will support standard alphanumeric characters, special characters, and a Caps Lock feature.
Preview of final output: Let us have a look at how the final output will look like.

Prerequisites:
Approach:
- Create an HTML file (index.html) to serve as the main structure for the virtual keyboard.
- Include a <textarea> element where the typed text will appear.
- Add a <div> element to represent the virtual keyboard. We'll generate the keyboard keys dynamically using JavaScript.
- Create a style.css file to style the virtual keyboard and its keys.
- Define styles for the keyboard layout, keys, background colors, fonts, and any other visual elements.
- Customize the appearance to match your design preferences.
- Create a script.js file to handle the functionality of the virtual keyboard.
- Dynamically generate the keyboard keys using JavaScript and insert them into the <div> element with the id "keyboard."
- Add event listeners to the keys to capture click events.
- Handle key clicks and update the text in the <textarea> accordingly.
- Implement the Caps Lock feature to toggle between uppercase and lowercase characters.
Example: Below is the implementation of project
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport"
content="width=device-width,
initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<link href=
"https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<title>
Virtual Keyboard
</title>
</head>
<body>
<textarea name="anytext"
class="text-area use-keyboard-input"
placeholder="Click me!">
</textarea>
<script src="script.js"></script>
</body>
</html>
/* style.css */
.text-area {
padding: 5px;
width: calc(100vw - 30px);
height: calc(100vh - 295px);
}
.keyboard {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
padding: 5px 0;
background: #004134;
box-shadow: 0 0 50px rgba(0, 0, 0, 0.5);
transition: bottom 0.4s;
}
.keyboard--hidden {
bottom: -100%;
}
.keyboard__keys {
text-align: center;
}
.keyboard__key {
height: 45px;
width: 6%;
max-width: 90px;
margin: 3px;
border-radius: 4px;
border: none;
background: rgba(255, 255, 255, 0.2);
color: white;
font-size: 1.05rem;
outline: none;
cursor: pointer;
display: inline-flex;
justify-content: center;
align-items: center;
vertical-align: top;
padding: 0;
-webkit-tap-highlight-color: transparent;
position: relative;
}
.keyboard__key:active {
background: rgba(255, 255, 255, 0.12);
}
.keyboard__key--wide {
width: 12%;
}
.keyboard__key--extra--wide {
width: 36%;
max-width: 500px;
}
.keyboard__key--activatable::after {
content: "";
position: absolute;
top: 10px;
right: 10px;
width: 8px;
height: 8px;
background: rgba(0, 0, 0, 0.4);
border-radius: 50%;
}
.keyboard__key--active::after {
background: #08ff00;
}
.keyboard__key--dark {
background: rgba(0, 0, 0, 0.25);
}
// script.js
const Keyboard = {
elements: {
main: null,
keysContainer: null,
keys: [],
capsKey: null,
},
properties: {
value: "",
capsLock: false,
keyboardInputs: null,
keyLayout: [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"0",
"backspace",
"q",
"w",
"e",
"r",
"t",
"y",
"u",
"i",
"o",
"p",
"caps",
"a",
"s",
"d",
"f",
"g",
"h",
"j",
"k",
"l",
"enter",
"done",
"z",
"x",
"c",
"v",
"b",
"n",
"m",
",",
".",
"?",
"space",
],
},
init() {
// create and setup main element
this.elements.main =
document.createElement("div");
this.elements.main.classList
.add("keyboard", "keyboard--hidden");
document.body
.appendChild(this.elements.main);
// create and setup child container component
this.elements.keysContainer =
document.createElement("div");
this.elements.keysContainer
.classList.add("keyboard__keys");
this.elements.main
.appendChild(this.elements.keysContainer);
// create and setup key elements
this.elements.keysContainer
.appendChild(this._createKeys());
this.elements.keys =
this.elements.keysContainer
.querySelectorAll(".keyboard__key");
// open keyboard for elements with .use-keyboard-input
this.properties.keyboardInputs =
document.querySelectorAll(
".use-keyboard-input"
);
this.properties
.keyboardInputs
.forEach((element) => {
element.addEventListener("focus", () => {
this
.open(element.value, (currentValue) => {
element.value = currentValue;
});
});
});
},
_createIconHTML(icon_name) {
return `<span class="material-icons">${icon_name}</span>`;
},
_createKeyBtn(iconName, class1, onclick, class2) {
this.keyElement =
document.createElement("button");
// add common attributes and classes
this.keyElement
.setAttribute("type", "button");
this.keyElement
.classList.add("keyboard__key");
// add specific listeners and classes
this.keyElement
.classList.add(class1, class2);
this.keyElement.innerHTML =
this._createIconHTML(iconName);
this.keyElement
.addEventListener("click", onclick);
},
_createKeys() {
const fragment =
document.createDocumentFragment();
this.properties.keyLayout.forEach((key) => {
const insertLineBreak =
["backspace", "p", "enter", "?"].indexOf(key) !== -1;
switch (key) {
case "backspace":
this._createKeyBtn(
"backspace", "keyboard__key--wide",
() => {
this.properties.value =
this.properties.value.slice(0, -1);
this._updateValueInTarget();
});
break;
case "caps":
this._createKeyBtn(
"keyboard_capslock",
"keyboard__key--activatable",
() => {
this.elements.capsKey
.classList
.toggle("keyboard__key--active");
this._toggleCapsLock();
},
"keyboard__key--wide"
);
this.elements.capsKey = this.keyElement;
break;
case "enter":
this._createKeyBtn(
"keyboard_return", "keyboard__key--wide",
() => {
this.properties.value += "\n";
this._updateValueInTarget();
});
break;
case "space":
this._createKeyBtn(
"space_bar", "keyboard__key--extra--wide",
() => {
this.properties.value += " ";
this._updateValueInTarget();
});
break;
case "done":
this._createKeyBtn(
"check_circle",
"keyboard__key--dark",
() => {
this.close();
this._updateValueInTarget();
},
"keyboard__key--wide"
);
break;
default:
this._createKeyBtn();
this.keyElement.textContent =
key.toLowerCase();
this.keyElement
.addEventListener(
"click",
() => {
this.properties.value +=
this.properties.capsLock
? key.toUpperCase()
: key.toLowerCase();
this._updateValueInTarget();
});
break;
}
fragment.appendChild(this.keyElement);
if (insertLineBreak) {
fragment
.appendChild(document.createElement("br"));
}
});
return fragment;
},
_updateValueInTarget() {
this.properties
.keyboardInputs
.forEach((keyboard) => {
keyboard.value =
this.properties.value;
});
},
_toggleCapsLock() {
this.properties.capsLock =
!this.properties.capsLock;
for (let key of this.elements.keys) {
if (key.childElementCount === 0) {
key.textContent =
this.properties.capsLock
? key.textContent.toUpperCase()
: key.textContent.toLowerCase();
}
}
},
open(initialValue, oninput) {
this.properties.value =
initialValue || "";
this.elements.main
.classList
.remove("keyboard--hidden");
},
close() {
this.properties.value =
this.properties.value;
this.elements.main
.classList.add("keyboard--hidden");
},
};
window.addEventListener("DOMContentLoaded", function () {
Keyboard.init();
});
Output: