Open In App

Build a Virtual Keyboard in Tailwind CSS

Last Updated : 13 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

We will create a virtual keyboard with a responsive design, animated transitions, and colored keys using the Tailwind CSS. It will be responsive for all the devices.

hhhh1

Prerequisites

Approach

  • Use Tailwind CSS for the styling and layout.
  • Implement JavaScript for the keyboard functionality and animation.
  • Create a virtual keyboard with the keys for letters, numbers and special characters.
  • Add animations for the key press and caps lock.
  • Ensure the keyboard is responsive and works across different devices.

Example: This example shows the implementation of the above-explained approach.

HTML
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,
                                   initial-scale=1.0">
    <title>The Virtual Keyboard</title>
    <link href=
"https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css"
          rel="stylesheet">
    <link href=
"https://fonts.googleapis.com/icon?family=Material+Icons"
          rel="stylesheet">
    <style>
        .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: #000000;
            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;
            transition: background-color 0.3s, transform 0.1s;
        }

        .keyboard__key:hover {
            background-color: rgba(255, 255, 255, 0.3);
        }

        .keyboard__key:active {
            background-color: rgba(255, 255, 255, 0.5);
            transform: scale(0.95);
        }

        .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(255, 255, 255, 0.7);
            border-radius: 50%;
        }

        .keyboard__key--active::after {
            background: #08ff00;
        }

        .keyboard__key--dark {
            background: rgba(0, 0, 0, 0.35);
        }
    </style>
</head>

<body class="bg-gray-400 p-4">
    <textarea name="anytext" 
              class="text-area use-keyboard-input" 
              placeholder="Click me!"></textarea>
    <script>
        class VirtualKeyboard {
            constructor() {
                this.elements = {
                    main: null,
                    keysContainer: null,
                    keys: [],
                    capsKey: null,
                };
                this.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() {
                this.elements.main = document
                  .createElement("div");
                this.elements.main.classList
                  .add("keyboard", "keyboard--hidden");
                document.body
                  .appendChild(this.elements.main);
                this.elements.keysContainer = document
                  .createElement("div");
                this.elements.keysContainer
                  .classList.add("keyboard__keys");
                this.elements.main
                  .appendChild(this.elements.keysContainer);
                this.elements.keysContainer
                  .appendChild(this._createKeys());
                this.elements.keys = this.elements
                  .keysContainer.querySelectorAll(".keyboard__key");
                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) {
                const keyElement = document.createElement("button");
                keyElement.setAttribute("type",
                                        "button");
                keyElement.classList.add("keyboard__key");
                keyElement.classList.add(class1,
                                         class2);
                keyElement.innerHTML = this
                  ._createIconHTML(iconName);
                keyElement.addEventListener("click", onclick);
                return keyElement;
            }
            _createKeys() {
                const fragment = document.createDocumentFragment();
                this.properties.keyLayout.forEach((key) => {
                    const insertLineBreak = ["backspace",
                             "p", "enter", "?"].indexOf(key) !== -1;
                    switch (key) {
                        case "backspace":
                            fragment.appendChild(thi
                                                 s._createKeyBtn("backspace",
                                                 "keyboard__key--wide", () => {
                                this.properties.value = this
                                  .properties.value.slice(0, -1);
                                this._updateValueInTarget();
                            }));
                            break;
                        case "caps":
                            fragment.appendChild(this
              ._createKeyBtn("keyboard_capslock",
                     "keyboard__key--activatable", () => {
                                this.elements.capsKey
                                  .classList.toggle("keyboard__key--active");
                                this._toggleCapsLock();
                            }, "keyboard__key--wide"));
                            this.elements.capsKey = this
                              .elements.keys[this.elements.keys.length - 1];
                            break;
                        case "enter":
                            fragment.appendChild(this.
                                _createKeyBtn("keyboard_return",
                                   "keyboard__key--wide", () => {
                                this.properties.value += "\n";
                                this._updateValueInTarget();
                            }));
                            break;
                        case "space":

                        fragment.appendChild(this.
                                      _createKeyBtn("space_bar",
                                              "keyboard__key--extra--wide", () => {
                                this.properties.value += " ";
                                this._updateValueInTarget();
                            }));
                            break;
                        case "done":
                            fragment.appendChild(this.
                                _createKeyBtn("check_circle", 
                                 "keyboard__key--dark", () => {
                                this.close();
                                this._updateValueInTarget();
                            }, "keyboard__key--wide"));
                            break;
                        default:
                            const keyElement = this._createKeyBtn();
                            keyElement.textContent = key.toLowerCase();
                            keyElement.addEventListener("click", () => {
                                this.properties.value += this.properties.capsLock ?
                                  key.toUpperCase() : key.toLowerCase();
                                this._updateValueInTarget();
                            });
                            fragment.appendChild(keyElement);
                            break;
                    }
                    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 () {
            const keyboard = new VirtualKeyboard();
            keyboard.init();
        });
    </script>
</body>

</html>

Output:

hhhh1



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads