HOWTO · JavaScript
How to Simulate Keypress in JavaScript
Discover how to simulate keypress events in JavaScript. Learn using the dispatchEvent method and KeyboardEvent objects for simple and combination keypress simulations.
On this page
Web applications often need to react to keyboard input, and testing that behavior usually means pressing keys by hand. JavaScript can instead create a synthetic KeyboardEvent and deliver it to an element, so a script exercises the same listeners a real key press would trigger. This article shows how to build and dispatch those events, how listeners observe them, and where the simulation stops short of real user input.
How Synthetic Keyboard Events Work
When a user presses a key, the browser generates a sequence of trusted events: keydown when the key goes down, keypress for character-producing keys (now deprecated), and keyup when the key is released. A script cannot reproduce that physical input, but it can construct an equivalent event object and push it through the same dispatch path.
Two pieces make this work:
- The
KeyboardEventconstructor builds an event whose properties describe the press:keyholds the character value such as"a"or"Enter",codeidentifies the physical key such as"KeyA", and the flagsctrlKey,shiftKey,altKey, andmetaKeydescribe held modifiers. dispatchEventdelivers the event to a target element. Listeners run immediately — dispatch is synchronous — and when the event is created withbubbles: true, it continues up through the ancestors todocumentandwindow.
For comparison, here is the keypress event a real press of the a key produces, expanded in a browser console: isTrusted is true, and key, code, charCode, keyCode, and which hold the same values a script assigns through the init object.
Every event dispatched this way has isTrusted set to false instead, which distinguishes it from real user input. The final section explains what that difference means in practice.
Create and Dispatch a KeyboardEvent
The constructor takes an event type and an optional initializer object: new KeyboardEvent(type, init). Use "keydown" or "keyup" as the type; keypress still exists for compatibility but is deprecated, so new listeners should attach to keydown. The init object sets the properties a listener will read.
Once constructed, the event is sent with target.dispatchEvent(event). Register the listener before dispatching — a listener added afterward can never see an event that has already been delivered.
On a page, the listener is typically attached to window or an element and the event is dispatched on document.body; with bubbles: true the event climbs the ancestor chain so the window listener still fires:
<!DOCTYPE html>
<html>
<body>
<script>
// Register the listener first; dispatchEvent runs listeners synchronously.
window.addEventListener("keydown", function (event) {
if (event.key === "a") {
console.log(event);
}
});
// Build a synthetic keydown event for the "a" key.
const keyEvent = new KeyboardEvent("keydown", {
key: "a", // value a listener reads as event.key
code: "KeyA", // physical key position
keyCode: 97, // deprecated; only for legacy listeners
charCode: 97, // deprecated; only for legacy listeners
bubbles: true,
cancelable: true
});
// Deliver the event; the window listener receives it as it bubbles up.
document.body.dispatchEvent(keyEvent);
</script>
</body>
</html>
Because bubbles is set to true, the listener attached to window fires even though the event was dispatched on document.body. The listener logs the whole KeyboardEvent object; expanding it in the console shows type: "keydown", isTrusted: false, key: "a", code: "KeyA", and the legacy charCode and keyCode values of 97.
The same construction and dispatch pattern also runs outside a browser, which is handy for a quick listener check. Node.js has no DOM KeyboardEvent, so the script below defines an equivalent class only when one is not already provided — on a real page the built-in class takes over — and dispatches on a plain EventTarget, which exposes the same addEventListener/dispatchEvent interface as DOM elements.
Run this example:
// The DOM defines KeyboardEvent; Node does not, so this stand-in supplies
// the same fields when the script runs outside a browser.
if (typeof KeyboardEvent === "undefined") {
globalThis.KeyboardEvent = class extends Event {
constructor(type, init = {}) {
super(type, init);
this.key = init.key;
this.code = init.code;
this.ctrlKey = Boolean(init.ctrlKey);
this.shiftKey = Boolean(init.shiftKey);
this.altKey = Boolean(init.altKey);
this.metaKey = Boolean(init.metaKey);
}
};
}
const target = new EventTarget(); // stands in for a DOM element
// Register the listener first; dispatchEvent runs listeners synchronously.
target.addEventListener("keydown", function (event) {
if (event.key === "a") {
console.log(`keydown observed: key=${event.key} code=${event.code}`);
}
});
// Build and dispatch a synthetic keydown event for the "a" key.
const keyEvent = new KeyboardEvent("keydown", {
key: "a", // value a listener reads as event.key
code: "KeyA", // physical key position
bubbles: true,
cancelable: true
});
target.dispatchEvent(keyEvent);
keydown observed: key=a code=KeyA
A standalone EventTarget has no ancestors, so bubbles has no visible effect here; on a page it is the flag that carries the event up to document and window.
Handle a Keyboard Event on an Input
A common task is checking that a field’s own handler reacts to keyboard input. The page below has a text input and a button; clicking the button creates a keydown event and dispatches it directly on the input, so only listeners attached to that input (or its ancestors, via bubbling) observe it.
<!DOCTYPE html>
<html>
<head>
<title>Simulate Keypress Example</title>
</head>
<body>
<input type="text" id="textInput" placeholder="Input field">
<button id="simulateButton">Simulate Keypress</button>
<script>
const input = document.getElementById("textInput");
// The input's own listener observes the dispatched event.
input.addEventListener("keydown", function (event) {
if (event.key === "a") {
console.log("Keypress simulated: ", event.key);
}
});
// Clicking the button creates and dispatches the event.
document.getElementById("simulateButton").addEventListener("click", function () {
const keyEvent = new KeyboardEvent("keydown", {
key: "a",
code: "KeyA",
bubbles: true,
cancelable: true
});
input.dispatchEvent(keyEvent);
});
</script>
</body>
</html>
Save the file, open it in a browser, and click the button. The console logs Keypress simulated: a from the input’s listener:
Note that dispatching the event only notifies listeners — it does not put a into the field. A synthetic keydown never changes input.value; the character visible in the field above was typed for the screenshot. To fill the field from a script, assign input.value directly.
Simulate Modifier Keys
Combinations such as Ctrl+A are just a keydown whose modifier flags are set. Set key and code for the main key, then add a boolean flag for each held modifier — ctrlKey, shiftKey, altKey, or metaKey (metaKey is the Command key on macOS and the Windows key elsewhere). The listener then inspects those same properties. The script uses the same KeyboardEvent stand-in as the earlier example and dispatches on a plain EventTarget.
Run this example:
// Same stand-in as the first example so this script also runs where no
// DOM KeyboardEvent exists; in a browser the built-in class is used.
if (typeof KeyboardEvent === "undefined") {
globalThis.KeyboardEvent = class extends Event {
constructor(type, init = {}) {
super(type, init);
this.key = init.key;
this.code = init.code;
this.ctrlKey = Boolean(init.ctrlKey);
this.shiftKey = Boolean(init.shiftKey);
this.altKey = Boolean(init.altKey);
this.metaKey = Boolean(init.metaKey);
}
};
}
const target = new EventTarget();
// Listen for the combination on keydown.
target.addEventListener("keydown", function (event) {
if (event.ctrlKey && event.key === "a") {
console.log("Ctrl+A keypress simulated");
}
});
const event = new KeyboardEvent("keydown", {
key: "a",
code: "KeyA",
ctrlKey: true, // marks Ctrl as held during this event
bubbles: true,
cancelable: true
});
target.dispatchEvent(event);
Ctrl+A keypress simulated
On a real page the identical listener and construction code runs against the built-in KeyboardEvent; attach the listener to window or dispatch on document.body to reach the whole document. The console shows the listener’s message:
If the code under test tracks a full press-and-release, dispatch a matching keyup event afterward so both halves of the sequence are observed.
Understand the Limits of Synthetic Events
Synthetic events are useful for testing your own handlers, but they are not a stand-in for real input:
event.isTrustedisfalse, so a listener can always tell a dispatched event from a genuine key press, and the browser withholds privileged behavior from untrusted events.- Dispatching a
keydownorkeyupon an input never changes itsvalue, moves the caret, or producesbeforeinput/inputevents — no text is typed. - Keyboard-triggered browser actions do not run for untrusted key events: Ctrl+A does not select all, Tab does not move focus, and F5 does not reload the page. Other activation behavior can still run for some synthetic events; for example, a dispatched click can toggle a checkbox or activate a link.
- The
keypressevent type and the numerickeyCode/charCode/whichproperties are deprecated; preferkeydown/keyupwithkeyandcode.
For unit tests and decoupled application logic, constructing a KeyboardEvent and calling dispatchEvent is enough. When you need a browser to behave exactly as if a user typed — trusted input, real focus changes, and default actions — drive it with an automation tool such as Playwright, Puppeteer, or WebDriver instead.