Open In App

Build a Virtual Keyboard using HTML CSS & JavaScript

Last Updated : 31 Jul, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

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.

virtual-keyboard-preview
virtual keyboard

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

HTML
<!-- 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>
CSS
/* 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);
}
JavaScript
// 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:


Next Article

Similar Reads