Simple-Keyboard: JavaScript Virtual Keyboard
Simple-Keyboard is a robust, lightweight, and highly customizable JavaScript virtual keyboard library designed for web applications. Currently at version 3.8.133, it maintains a stable release cadence with frequent updates addressing bugs and adding features. Key differentiators include broad browser compatibility (down to IE11 with specific bundles), built-in TypeScript support since v3.0.0, and a modular architecture allowing extensions for autocorrect, input masks, and key navigation. It is designed to be framework-agnostic, easily integrating into vanilla JavaScript, React, Angular, and Vue projects, providing an on-screen input solution suitable for touchscreens, kiosks, and general web input fields.
Common errors
-
TypeError: SimpleKeyboard is not a constructor
cause Attempting to instantiate `SimpleKeyboard` using incorrect import syntax (e.g., named import for a default export) or incorrect CommonJS `require` for ESM interop.fixEnsure you are using a default import: `import SimpleKeyboard from 'simple-keyboard';`. For CommonJS, `const SimpleKeyboard = require('simple-keyboard');` should correctly resolve the default export. -
ReferenceError: document is not defined
cause `simple-keyboard` is a DOM-dependent library. This error occurs when attempting to initialize or interact with the keyboard in a non-browser environment, such as during Server-Side Rendering (SSR) without proper hydration or a mocked DOM.fixEnsure `simple-keyboard` initialization code is executed only in a client-side (browser) environment. For SSR applications, use dynamic imports with a `typeof window !== 'undefined'` check or a dedicated SSR solution to defer client-side code. -
Argument of type 'HTMLElement | null' is not assignable to parameter of type 'string | HTMLInputElement'
cause In TypeScript, `document.querySelector` can return `null` or a generic `Element`, neither of which directly satisfies `simple-keyboard`'s `input` option (which expects `string | HTMLInputElement`).fixAdd a type assertion to `HTMLInputElement` and ensure the element exists before passing it: `document.querySelector('.input') as HTMLInputElement;` then check if `inputElement` is not `null` before passing, or pass the CSS selector string directly to `input`.
Warnings
- breaking As of `simple-keyboard` v3.5.0, the `display` option's styling rules were extended to also affect `layoutCandidates` box items. This could lead to unexpected visual changes if you previously relied on separate styling for these elements.
- breaking In `simple-keyboard` v3.1.0, the `{delete}` button's functionality was changed to perform forward deletion (deleting characters *after* the caret). If your application used a button named `{delete}` and expected it to behave like a backspace, its behavior will have changed.
- breaking Version 3.0.0 of `simple-keyboard` introduced a simplified module architecture. Custom modules are now simple functions that receive the `keyboard` instance as a parameter, replacing previous module integration patterns. Existing custom modules will require refactoring.
- gotcha Prior to v3.7.0, `simple-keyboard` primarily provided CommonJS modules. From v3.7.0 onwards, an ESM output (`index.modern.esm.js`) is included. Mixing import styles (e.g., using `require` in an ESM context) or incorrect module resolution for versions `>=3.7.0` can lead to runtime errors.
- gotcha In `simple-keyboard` v3.4.0, the TypeScript type definitions were relocated from `build/types` directly to the `build` directory. This internal change could potentially affect projects with highly customized `tsconfig.json` configurations or those relying on absolute paths to type declaration files.
- gotcha `simple-keyboard` supports IE11 but requires using the `index.js` bundle. The `index.modern.js` bundle (introduced in v3.3.0) and ESM outputs are optimized for modern browsers and will not function correctly in IE11.
Install
-
npm install simple-keyboard -
yarn add simple-keyboard -
pnpm add simple-keyboard
Imports
- SimpleKeyboard
import { SimpleKeyboard } from 'simple-keyboard';import SimpleKeyboard from 'simple-keyboard';
- KeyboardOptions
import type { KeyboardOptions } from 'simple-keyboard'; - CSS Styles
import 'simple-keyboard/build/css/index.css';
Quickstart
import SimpleKeyboard from 'simple-keyboard';
import 'simple-keyboard/build/css/index.css';
// Create a target input element in your HTML: <input class="input" value="" />
// And a container for the keyboard: <div class="simple-keyboard"></div>
const inputElement = document.querySelector('.input') as HTMLInputElement;
const keyboard = new SimpleKeyboard({
onChange: (input: string) => onChange(input),
onKeyPress: (button: string) => onKeyPress(button),
input: inputElement || undefined, // Pass the input element or its selector
theme: 'hg-theme-default hg-layout-default',
layout: {
default: [
'q w e r t y u i o p',
'a s d f g h j k l',
'{shift} z x c v b n m {backspace}',
'{numbers} {space} {ent}'
],
shift: [
'Q W E R T Y U I O P',
'A S D F G H J K L',
'{shift} Z X C V B N M {backspace}',
'{numbers} {space} {ent}'
],
numbers: [
'1 2 3',
'4 5 6',
'7 8 9',
'{abc} 0 .'
]
}
});
function onChange(input: string) {
if (inputElement) {
inputElement.value = input;
}
console.log('Input changed:', input);
}
function onKeyPress(button: string) {
console.log('Button pressed:', button);
if (button === '{shift}' || button === '{lock}') {
handleShift();
}
if (button === '{numbers}' || button === '{abc}') {
handleLayoutChange(button);
}
}
function handleShift() {
const currentLayout = keyboard.options.layoutName;
const newLayout = currentLayout === 'default' ? 'shift' : 'default';
keyboard.setOptions({ layoutName: newLayout });
}
function handleLayoutChange(button: string) {
const newLayout = button === '{numbers}' ? 'numbers' : 'default';
keyboard.setOptions({ layoutName: newLayout });
}