Web Kokua Banner Image


Events

Events are things that happen in the system you are programming, which the system tells you about so your code can react to them. For example, if the user clicks a button on a webpage, you might want to react to that action by displaying an information box. In this article, we discuss some important concepts surrounding events, and look at the fundamentals of how they work in browsers.

Events are things that happen in the system you are programming, the system produces (or "fires") a signal of some kind when an event occurs, and provides a mechanism by which an action can be automatically taken (that is, some code running) when the event occurs. Events are fired inside the browser window, and tend to be attached to a specific item that resides in it. This might be a single element, a set of elements, the HTML document loaded in the current tab, or the entire browser window. There are many different types of events that can occur.

For example:

To react to an event, you attach an event handler to it. This is a block of code (usually a JavaScript function that you as a programmer create) that runs when the event fires. When such a block of code is defined to run in response to an event, we say we are registering an event handler. Note: Event handlers are sometimes called event listeners, they are pretty much interchangeable for our purposes, although strictly speaking, they work together. The listener listens out for the event happening, and the handler is the code that runs in response to it happening.

Web events are not part of the core JavaScript language — they are defined as part of the APIs built into the browser.


Event Bubbling

We've seen that a web page is composed of elements: headings, paragraphs of text, images, buttons, and so on, and that you can listen for events that happen to these elements. For example, you could add a listener to a button, and it will run when the user clicks the button.

We've also seen that these elements can be nested inside each other: for example, a <button> could be placed inside a <div> element. In this case we'd call the <div> element a parent element, and the <button> a child element.

window.addEventListener("DOMContentLoaded", (event) => { let bubDiv1 = document.getElementById("bubDiv1"); bubDiv1.addEventListener("click", handleClick1); function handleClick1(e) { let divResponse1 = document.getElementById("divResponse1"); divResponse1.innerHTML += `You clicked on a ${e.currentTarget.tagName} element
`; } });


You'll see that the parent fires a click event when the user clicks the button. This makes sense: the button is inside the <div>, so when you click the button you're also implicitly clicking the element it is inside.

What happens if we add event listeners to the button and the parent?

window.addEventListener("DOMContentLoaded", (event) => { let bubDiv2 = document.getElementById("bubDiv2"); let bubButton2 = document.getElementById("bubButton2"); bubDiv2.addEventListener("click", handleClick2); bubButton2.addEventListener("click", handleClick2); function handleClick2(e) { let divResponse2 = document.getElementById("divResponse2"); divResponse2.innerHTML += `You clicked on a ${e.currentTarget.tagName} element
`; } });


You'll see that both the div and the button fire a click event when the user clicks the button

How To Stop Bubbling

There may situations where you want to keep the event from bubbling. This can be done by calling the stopPropagation() function.

MyButton.addEventListener("click", (event) => { event.stopPropagation(); // MORE CODE HERE });

Event capture

An alternative form of event propagation is event capture. This is like event bubbling but the order is reversed: instead of the event firing first on the innermost element targeted, and then on successively less nested elements, the event fires first on the least nested element, and then on successively more nested elements, until the target is reached.

Event capture is disabled by default. To enable it you have to pass the capture option in addEventListener().

window.addEventListener("DOMContentLoaded", (event) => { let bubDiv3 = document.getElementById("bubDiv3"); let bubButton3 = document.getElementById("bubButton3"); bubDiv3.addEventListener("click", handleClick3, { capture: true }); bubButton3.addEventListener("click", handleClick3, { capture: true }); function handleClick3(e) { let divResponse = document.getElementById("divResponse3"); divResponse.innerHTML += `You clicked on a ${e.currentTarget.tagName} element
`; } });


Why bother with both capturing and bubbling? In the bad old days, when browsers were much less cross-compatible than now, Netscape only used event capturing, and Internet Explorer used only event bubbling. When the W3C decided to try to standardize the behavior and reach a consensus, they ended up with this system that included both, which is what modern browsers implement.

By default almost all event handlers are registered in the bubbling phase, and this makes more sense most of the time.


Event Delegation

In the last section, we looked at a problem caused by event bubbling and how to fix it. Event bubbling isn't just annoying, though: it can be very useful. In particular, it enables event delegation. In this practice, when we want some code to run when the user interacts with any one of a large number of child elements, we set the event listener on their parent and have events that happen on them bubble up to their parent rather than having to set the event listener on every child individually.

Let's go back to our first example, where we set the background color of the whole page when the user clicked a button. Suppose that instead, the page is divided into 16 tiles, and we want to set each tile to a random color when the user clicks that tile.

<div id="tile_container"> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> <div class="tile_div"></div> </div>
#tile_container { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 100px; } #tile_container div { border:1px solid #000; }
function random(number) { return Math.floor(Math.random() * number); } function bgChange() { const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`; return rndCol; } const tile_container = document.querySelector("#tile_container"); tile_container.addEventListener("click", (event) => { event.target.style.backgroundColor = bgChange(); });

In this example, we're using event.target to get the element that was the target of the event (that is, the innermost element). If we wanted to access the element that handled this event (in this case the container) we could use event.currentTarget.


target and currentTarget

If you look closely at the examples we've introduced in this page, you'll see that we're using two different properties of the event object to access the element that was clicked. In Setting a listener on a parent element we're using event.currentTarget. However, in Event delegation, we're using event.target.

The difference is that target refers to the element on which the event was initially fired, while currentTarget refers to the element to which this event handler has been attached.

While target remains the same while an event bubbles up, currentTarget will be different for event handlers that are attached to different elements in the hierarchy.

We can see this if we slightly adapt the Bubbling example above. We're using the same HTML as before:

<div id="bubDiv4" style="background-color:#000;height:5rem;padding:1rem;"> <input type="button" id="bubButton4" value="Click Me" class="btn btn-primary" /> </div> <div class="response" id="divResponse4"></div>
window.addEventListener("DOMContentLoaded", (event) => { let bubDiv4 = document.getElementById("bubDiv4"); let bubButton4 = document.getElementById("bubButton4"); bubDiv4.addEventListener("click", handleClick4, { capture: true }); bubButton4.addEventListener("click", handleClick4, { capture: true }); function handleClick4(e) { let divResponse = document.getElementById("divResponse4"); const logTarget = `Target: ${e.target.tagName}`; const logCurrentTarget = `Current target: ${e.currentTarget.tagName}`; divResponse.innerHTML += `${logTarget}, ${logCurrentTarget}<br/>`; } });



Common Event Types

There are a few events that are more common than others. The following is a list with descriptions of some of the more commonly used events.

Page Load This event is important mainly to make sure all elements and scripts have been loaded in the page before doing anything with them.
Click This occurs when an element is clicked on. Primarily this applies to buttons, but it can be just about any HTML element.
Change This occurs when ever something has changed. It's most commonly applied to drop down lists or list boxes, but can also apply to text in a text box or text area. Any element that has choices for values will generally fire a change event upon a change in the value.
Focus When an element gets focus or loses focus, events are fired.
Keyboard When a keyboard key is pressed and event is fired.
Mouse The mouse can fire several different events, such as coordinates, right-click and left-click.

Page Load Event

Any code that requires that all elements and scripts have been loaded prior to being invoked should be place within the contents of this event. This is the vanilla Javascript equivalent of jQuery's $(window).load(function() {});

window.addEventListener("DOMContentLoaded", (event) => { // CODE HERE });

Click Event

A click event most often applies to buttons, but it could be applied just about any HTML element that the user clicks on including images, div, span, or other form of input.

An element receives a click event when any of the following occurs:

If the button is pressed on one element and the pointer is moved outside the element before the button is released, the event is fired on the most specific ancestor element that contained both elements.

click fires after both the mousedown and mouseup events have fired, in that order.

The event is a device-independent event, meaning it can be activated by touch, keyboard, mouse, and any other mechanism provided by assistive technology.

Syntax

addEventListener("click", (event) => {}); onclick = (event) => {};

<input type="button" id="MyButton" name="MyButton" value="Click Me" class="MyButtonClass" /> let MyButton = document.getElementById("MyButton"); MyButton.addEventListener("click", MyButtonHandler); function MyButtonHandler() { // CODE HERE } OR MyButton.addEventListener("click", () => { // CODE HERE });

Programatically Initiating A Click Event

let MyDiv = = document.getElementById("MyDiv"); // THIS WILL CREATE A CLICK EVENT ON MyDiv MyDiv.click(); // THIS WILL ALSO CREATE A CLICK EVENT ON MyDiv MyDiv.dispatchEvent(new Event('click'));

Change Event

The change event is fired for <input>, <select>, and <textarea> elements when the user modifies the element's value. Unlike the input event, the change event is not necessarily fired for each alteration to an element's value.

Depending on the kind of element being changed and the way the user interacts with the element, the change event fires at a different moment:

addEventListener("change", (event) => {}); onchange = (event) => {};

window.addEventListener("DOMContentLoaded", (event) => { let ddlBands = document.getElementById("ddlBands"); ddlBands.addEventListener("change", handleChange1); function handleChange1(e) { let divResponse = document.getElementById("divResponse5"); divResponse.innerHTML = "Band Chosen Is: " + ddlBands.options[ddlBands.options.selectedIndex].value; } });



Focus Event

<input type="text" id="FocusText" name="FocusText" class="form-control" value="" /> <div class="response" id="divResponse6"></div>
window.addEventListener("DOMContentLoaded", (event) => { let FocusText = document.getElementById("FocusText"); let btnSetFocus = document.getElementById("btnSetFocus"); FocusText.addEventListener("focus", handleFocus1); btnSetFocus.addEventListener("click", handleSetFocus1); function handleFocus1(e) { let divResponse = document.getElementById("divResponse6"); divResponse.innerHTML = "Texbox Has Focus"; } function handleSetFocus1(e) { let divResponse = document.getElementById("divResponse6"); FocusText.focus(); } });




Keyboard Event

KeyboardEvent objects describe a user interaction with the keyboard; each event describes a single interaction between the user and a key (or combination of a key with modifier keys) on the keyboard. The event type (keydown, keypress, or keyup) identifies what kind of keyboard activity occurred.

KeyboardEvent events just indicate what interaction the user had with a key on the keyboard at a low level, providing no contextual meaning to that interaction. When you need to handle text input, use the input event instead. Keyboard events may not be fired if the user is using an alternate means of entering text, such as a handwriting system on a tablet or graphics tablet.


The KeyboardEvent() constructor creates a new KeyboardEvent object.


new KeyboardEvent(type) new KeyboardEvent(type, options)
Parameters
Parameter Description
type A string with the name of the event. It is case-sensitive and browsers set it to keydown, keyup, or keypress.
options An object that, in addition of the properties defined in UIEvent(), can have the following properties:
Options
Option Description
key (Optional) A string, defaulting to "", that sets the value of KeyboardEvent.key.
code (Optional) A string, defaulting to "", that sets the value of KeyboardEvent.code.
location (Optional) A string, defaulting to 0, that sets the value of KeyboardEvent.location.
repeat (Optional) A boolean value, defaulting to false, that sets the value of KeyboardEvent.repeat.
isComposing (Optional) A boolean value, defaulting to false, that sets the value of KeyboardEvent.isComposing.
charCode (Optional Deprecated) A number, defaulting to 0, that sets the value of the deprecated KeyboardEvent.charCode.
keyCode (Optional Deprecated) A number, defaulting to 0, that sets the value of the deprecated KeyboardEvent.keyCode.
which (Optional Deprecated) A number, defaulting to 0, that sets the value of the deprecated UIEvent.which.
ctrlKey (Optional) A boolean value, defaulting to false, that sets the value of KeyboardEvent.ctrlKey.
shiftKey (Optional) A boolean value, defaulting to false, that sets the value of KeyboardEvent.shiftKey.
altKey (Optional) A boolean value, defaulting to false, that sets the value of KeyboardEvent.altKey.
metaKey (Optional) A boolean value, defaulting to false, that sets the value of KeyboardEvent.metaKey.

Constants

The KeyboardEvent interface defines the following constants.


Keyboard Locations

The following constants identify which part of the keyboard the key event originates from.

They are accessed as KeyboardEvent.DOM_KEY_LOCATION_STANDARD and so forth.


Keyboard location identifiers
Constant Value Description
DOM_KEY_LOCATION_STANDARD 0x00 The key described by the event is not identified as being located in a particular area of the keyboard; it is not located on the numeric keypad (unless it's the NumLock key), and for keys that are duplicated on the left and right sides of the keyboard, the key is, for whatever reason, not to be associated with that location.
 
Examples include alphanumeric keys on the standard PC 101 US keyboard, the NumLock key, and the space bar.
DOM_KEY_LOCATION_LEFT 0x01 The key is one which may exist in multiple locations on the keyboard and, in this instance, is on the left side of the keyboard.
 
Examples include the left Control key, the left Command key on a Macintosh keyboard, or the left Shift key.
DOM_KEY_LOCATION_RIGHT 0x02 The key is one which may exist in multiple positions on the keyboard and, in this case, is located on the right side of the keyboard.
 
Examples include the right Shift key and the right Alt key (Option on a Mac keyboard).
DOM_KEY_LOCATION_NUMPAD 0x03 The key is located on the numeric keypad, or is a virtual key associated with the numeric keypad if there's more than one place the key could originate from. The NumLock key does not fall into this group and is always encoded with the location DOM_KEY_LOCATION_STANDARD.
 
Examples include the digits on the numeric keypad, the keypad's Enter key, and the decimal point on the keypad.

Instance Properties

This interface also inherits properties of its parents, UIEvent and Event.
All of the following properties are read only.

Instance Properties
Property Description
KeyboardEvent.altKey Returns a boolean value that is true if the Alt (Option or ⌥ on macOS) key was active when the key event was generated.
KeyboardEvent.code Returns a string with the code value of the physical key represented by the event.

Warning: This ignores the user's keyboard layout, so that if the user presses the key at the "Y" position in a QWERTY keyboard layout (near the middle of the row above the home row), this will always return "KeyY", even if the user has a QWERTZ keyboard (which would mean the user expects a "Z" and all the other properties would indicate a "Z") or a Dvorak keyboard layout (where the user would expect an "F"). If you want to display the correct keystrokes to the user, you can use Keyboard.getLayoutMap().

KeyboardEvent.ctrlKey Returns a boolean value that is true if the Ctrl key was active when the key event was generated.
KeyboardEvent.isComposing Returns a boolean value that is true if the event is fired between after compositionstart and before compositionend.
KeyboardEvent.key Returns a string representing the key value of the key represented by the event.
KeyboardEvent.location Returns a number representing the location of the key on the keyboard or other input device. A list of the constants identifying the locations is shown above in Keyboard locations.
KeyboardEvent.metaKey Returns a boolean value that is true if the Meta key (on Mac keyboards, the ⌘ Command key; on Windows keyboards, the Windows key (⊞)) was active when the key event was generated.
KeyboardEvent.repeat Returns a boolean value that is true if the key is being held down such that it is automatically repeating.
KeyboardEvent.shiftKey Returns a boolean value that is true if the Shift key was active when the key event was generated.

Instance methods

This interface also inherits methods of its parents, UIEvent and Event.

KeyboardEvent.getModifierState()

Returns a boolean value indicating if a modifier key such as Alt, Shift, Ctrl, or Meta, was pressed when the event was created.


Events

The following events are based on the KeyboardEvent type. In the list below, each event links to the documentation for the Element handler for the event, which applies generally to all of the recipients, including Element, Document, and Window.

keydown A key has been pressed.
keyup A key has been released.
keypress A key that normally produces a character value has been pressed. This event was highly device-dependent and is obsolete. You should not use it.

Sequence of Events

  1. When the key is first pressed, the keydown event is sent.
  2. If the key is not a modifier key, the keypress event is sent.
  3. When the user releases the key, the keyup event is sent.

Special Cases

Some keys toggle the state of an indicator light; these include keys such as Caps Lock, Num Lock, and Scroll Lock. On Windows and Linux, these keys dispatch only the keydown and keyup events.


Keydown Event

The keydown event is fired when a key is pressed.

Unlike the deprecated keypress event, the keydown event is fired for all keys, regardless of whether they produce a character value.

The keydown and keyup events provide a code indicating which key is pressed, while keypress indicates which character was entered. For example, a lowercase "a" will be reported as 65 by keydown and keyup, but as 97 by keypress. An uppercase "A" is reported as 65 by all events.

The event target of a key event is the currently focused element which is processing the keyboard activity. This includes: <input>, <textarea>, anything that is contentEditable, and anything else that can be interacted with the keyboard, such as <a>, <button>, and <summary>. If no suitable element is in focus, the event target will be the <body> or the root. The event bubbles. It can reach Document and Window.

The event target might change between different key events. For example, the keydown target for pressing the Tab key would be different from the keyup target, because the focus has changed.

addEventListener("keydown", (event) => {}); onkeydown = (event) => {};

<input type="text" id="keyDownText1" name="keyDownText1" class="form-control" value="" /> <div class="response" id="divResponse7"></div>
window.addEventListener("DOMContentLoaded", (event) => { let keyDownText1 = document.getElementById("keyDownText1"); keyDownText1.addEventListener("keydown", handleKeyDown1); function handleKeyDown1(e) { let divResponse = document.getElementById("divResponse7"); divResponse.innerHTML += "KeyDown: " + e.code + "
"; } });



Keyup Event

The keyup event is fired when a key is released.


addEventListener("keyup", (event) => {}); onkeyup = (event) => {};

<input type="text" id="keyUpText1" name="keyUpText1" class="form-control" placeholder="Type Some Text" value="" /> <div class="response" id="divResponse8"></div>

window.addEventListener("DOMContentLoaded", (event) => { let keyUpText1 = document.getElementById("keyUpText1"); keyUpText1.addEventListener("keyup", handleKeyUp1); function handleKeyUp1(e) { let divResponse = document.getElementById("divResponse8"); divResponse.innerHTML += "KeyUp: " + e.code + "
"; } });



Looking At Both Key Down and Key Up

<input type="text" id="keyDownUpText1" name="keyDownUpText1" class="form-control" placeholder="Type Some Text" value="" /> <hr class="space1" /> <div class="row"> <div class="col-md-6"><h4>KeyDown</h4></div> <div class="col-md-6"><h4>KeyUp</h4></div> </div> <div class="row"> <div class="col-md-6"><div class="response" id="divResponse9"></div></div> <div class="col-md-6"><div class="response" id="divResponse10"></div></div> </div>

window.addEventListener("DOMContentLoaded", (event) => { let keyDownUpText1 = document.getElementById("keyDownUpText1"); keyDownUpText1.addEventListener("keydown", handleKeyDown2); keyDownUpText1.addEventListener("keyup", handleKeyUp2); function handleKeyDown2(e) { let divResponse = document.getElementById("divResponse9"); divResponse.innerHTML += "KeyDown: " + e.code + "
"; } function handleKeyUp2(e) { let divResponse = document.getElementById("divResponse10"); divResponse.innerHTML += "KeyUp: " + e.code + "
"; } });


KeyDown

KeyUp


Mouse Event

The MouseEvent interface represents events that occur due to the user interacting with a pointing device (such as a mouse). Common events using this interface include click, dblclick, mouseup, mousedown.

MouseEvent derives from UIEvent, which in turn derives from Event. Though the MouseEvent.initMouseEvent() method is kept for backward compatibility, creating of a MouseEvent object should be done using the MouseEvent() constructor.

Several more specific events are based on MouseEvent, including WheelEvent, DragEvent, and PointerEvent.

Event <--- UIEvent <--- MouseEvent

Constructor

MouseEvent() Creates a MouseEvent object.

Instance Properties

This interface also inherits properties of its parents, UIEvent and Event.

Instance Properties
Property Description
MouseEvent.altKey Returns true if the alt key was down when the mouse event was fired. Read only
MouseEvent.button The button number that was pressed (if applicable) when the mouse event was fired. Read only
MouseEvent.buttons The buttons being pressed (if any) when the mouse event was fired. Read only
MouseEvent.clientX The X coordinate of the mouse pointer in local (DOM content) coordinates. Read only
MouseEvent.clientY The Y coordinate of the mouse pointer in local (DOM content) coordinates. Read only
MouseEvent.ctrlKey Returns true if the control key was down when the mouse event was fired. Read only
MouseEvent.metaKey Returns true if the meta key was down when the mouse event was fired. Read only
MouseEvent.movementX The X coordinate of the mouse pointer relative to the position of the last mousemove event. Read only
MouseEvent.movementY The Y coordinate of the mouse pointer relative to the position of the last mousemove event. Read only
MouseEvent.offsetX The X coordinate of the mouse pointer relative to the position of the padding edge of the target node. Read only
MouseEvent.offsetY The Y coordinate of the mouse pointer relative to the position of the padding edge of the target node. Read only
MouseEvent.pageX The X coordinate of the mouse pointer relative to the whole document. Read only
MouseEvent.pageY The Y coordinate of the mouse pointer relative to the whole document. Read only
MouseEvent.relatedTarget The secondary target for the event, if there is one. Read only
MouseEvent.screenX The X coordinate of the mouse pointer in global (screen) coordinates. Read only
MouseEvent.screenY The Y coordinate of the mouse pointer in global (screen) coordinates. Read only
MouseEvent.shiftKey Returns true if the shift key was down when the mouse event was fired. Read only
MouseEvent.x Alias for MouseEvent.clientX. Read only
MouseEvent.y Alias for MouseEvent.clientY. Read only

altKey Property
<h3>altKey</h3> <div class="response" id="divResponse11"></div>
window.addEventListener("DOMContentLoaded", (event) => { let divResponse11 = document.getElementById("divResponse11"); divResponse11.addEventListener("click", handleClick5); function handleClick5(e) { divResponse11.innerHTML = "The alt key is pressed: "+ e.altKey; } });

altKey

Click on the mouse in the shaded div below. Try with aly key pressed and without.



Mouse Button
<div class="response" id="divResponse12" oncontextmenu="event.preventDefault();"></div>
window.addEventListener("DOMContentLoaded", (event) => { let divResponse12 = document.getElementById("divResponse12"); divResponse12.addEventListener("mouseup", handleClick6); function handleClick6(e) { let strResp = ""; switch (e.button) { case 0: strResp = "Left button clicked."; break; case 1: strResp = "Middle button clicked."; break; case 2: strResp = "Right button clicked."; break; default: strResp = "Unknown button code: " + e.button; } divResponse12.innerHTML = "Action: "+ strResp; } });

Click on the mouse in the shaded div below. Try with right, left and middle mouse buttons if posible.


Mouse Position

<div class="response" id="divResponse13"> <p>Move your mouse to see its position.</p> <p id="screen_log6"></p> </div>
window.addEventListener("DOMContentLoaded", (event) => { let divResponse13 = document.getElementById("divResponse13"); divResponse13.addEventListener("mousemove", handleMove1); function handleMove1(e) { let screenLog = document.getElementById("screen_log6"); screenLog.innerText = ` Screen X/Y: ${e.screenX}, ${e.screenY} Client X/Y: ${e.clientX}, ${e.clientY}`; } });

Move your mouse to see its position.


Mouse Position

<div class="response" id="divResponse14"> <p>Click your mouse to see its position.</p> <p id="screen_log8"></p> </div>

window.addEventListener("DOMContentLoaded", (event) => { let divResponse14 = document.getElementById("divResponse14"); divResponse14.addEventListener("click", handleClick7); function handleClick7(e) { let screenLog = document.getElementById("screen_log8"); screenLog.innerHTML = "Screen X:" + e.screenX + " Screen Y:" + e.screenY + "
Client X:" + e.clientX + " Client Y:" + e.clientY; } });

Click your mouse to see its position.







class MyEventTarget extends EventTarget { constructor(mySecret) { super(); this._secret = mySecret; } get secret() { return this._secret; } } let myEventTarget = new MyEventTarget(5); let value = myEventTarget.secret; // === 5 myEventTarget.addEventListener("foo", (e) => { myEventTarget._secret = e.detail; }); let event = new CustomEvent("foo", { detail: 7 }); myEventTarget.dispatchEvent(event); let newValue = myEventTarget.secret; // === 7
Instance Methods
EventTarget.addEventListener() Registers an event handler of a specific event type on the EventTarget.
EventTarget.removeEventListener() Removes an event listener from the EventTarget.
EventTarget.dispatchEvent() Dispatches an event to this EventTarget.