Web Development /JavaScript Programming / Lesson
Web Development

JavaScript Events and Event Handling

Learn how JavaScript responds to user actions and browser events using event listeners, event objects, event handlers, keyboard events, mouse events, form events and event propagation.

🎯

Learning Objectives

["Understand what browser events are and why they are important.","Identify common JavaScript events such as click, input, submit, change, keydown and mouseover.","Understand the difference between an event and an event handler.","Use addEventListener() to attach event listeners.","Create event handler functions using normal and arrow functions.","Understand the Event object and commonly used event properties.","Work with mouse and pointer events.","Work with keyboard events and keyboard properties.","Handle input, change and submit events.","Prevent default browser behavior with preventDefault().","Understand event bubbling and event propagation.","Use stopPropagation() when stopping propagation is appropriate.","Use event delegation for dynamically generated elements.","Remove event listeners correctly with removeEventListener().","Build practical interactive interfaces using JavaScript events."]

📖

Lesson Content

Introduction

A modern website is not simply a collection of HTML elements. Users interact with buttons, forms, menus, links, inputs, cards and other interface components.

JavaScript makes it possible for a webpage to respond to those interactions.

For example, when a user clicks a button, JavaScript can:

  • Change text.
  • Open a menu.
  • Display a message.
  • Show or hide content.
  • Submit information.
  • Update a progress indicator.
  • Change a CSS class.
  • Load information from a server.

The mechanism that allows JavaScript to respond to these actions is called event handling.

What Is an Event?

An event is an occurrence detected by the browser.

Examples include:

  • A user clicking a button.
  • A user typing into an input field.
  • A keyboard key being pressed.
  • A form being submitted.
  • A mouse moving over an element.
  • A page finishing its initial loading process.
  • An input value changing.

JavaScript can listen for these events and execute code when they happen.

What Is an Event Handler?

An event handler is code that runs in response to an event.

For example:

function showMessage() {
    console.log('Button clicked.');
}

The function itself does not run until it is connected to an event.

addEventListener()

The modern and recommended way to attach event handlers is the addEventListener() method.

Basic syntax:

element.addEventListener('event', function);

Example:

const button = document.querySelector('#save-button');

button.addEventListener('click', function() {
    console.log('Save button clicked.');
});

When the user clicks the button, the function runs.

Using an Arrow Function

Arrow functions can also be used as event handlers.

const button = document.querySelector('#save-button');

button.addEventListener('click', () => {
    console.log('Save button clicked.');
});

This syntax is common in modern JavaScript applications.

Named Event Handler Functions

You can define the function separately.

function handleSave() {
    console.log('Saving data...');
}

const button = document.querySelector('#save-button');

button.addEventListener('click', handleSave);

Notice that the function is passed without parentheses.

Correct:

button.addEventListener('click', handleSave);

Incorrect:

button.addEventListener('click', handleSave());

The second example calls the function immediately instead of giving addEventListener() a function to run later.

Common JavaScript Events

Some commonly used browser events include:

EventTypical Use
clickButton or element clicks
dblclickDouble clicks
mouseenterPointer enters an element
mouseleavePointer leaves an element
keydownKeyboard key is pressed
keyupKeyboard key is released
inputInput value changes while typing
changeForm control value changes
submitForm is submitted
focusElement receives focus
blurElement loses focus
DOMContentLoadedHTML document has been parsed

Handling Click Events

The click event is one of the most commonly used events.

HTML:

<button id="welcome-button">
    Click Me
</button>

JavaScript:

const button = document.querySelector('#welcome-button');

button.addEventListener('click', () => {
    console.log('Welcome!');
});

Changing Content After a Click

const button = document.querySelector('#welcome-button');

const message = document.querySelector('#message');

button.addEventListener('click', () => {
    message.textContent = 'Welcome to JavaScript!';
});

This combines DOM selection, events and DOM manipulation.

Changing a CSS Class on Click

button.addEventListener('click', () => {
    message.classList.toggle('visible');
});

This technique is commonly used for:

  • Mobile menus.
  • Dropdowns.
  • Modals.
  • Tabs.
  • Accordion sections.
  • Dark-mode controls.

The Event Object

When an event occurs, the browser provides information about that event.

This information is available through the Event object.

Example:

button.addEventListener('click', (event) => {
    console.log(event);
});

The event object contains information about what happened.

event.target

The target property identifies the element on which the event occurred.

button.addEventListener('click', (event) => {
    console.log(event.target);
});

This is especially useful when several elements share one event handler.

event.currentTarget

The currentTarget property identifies the element whose event listener is currently executing.

button.addEventListener('click', (event) => {
    console.log(event.currentTarget);
});

For a simple listener directly attached to the clicked button, target and currentTarget may refer to the same element.

They can differ when event propagation and event delegation are involved.

Mouse Events

JavaScript provides several events for pointer and mouse interactions.

For example:

const card = document.querySelector('.course-card');

card.addEventListener('mouseenter', () => {
    console.log('Pointer entered card.');
});

card.addEventListener('mouseleave', () => {
    console.log('Pointer left card.');
});

Pointer Events

Modern applications can also use pointer events, which provide a unified event model for different pointing devices.

Examples include:

  • pointerdown
  • pointerup
  • pointermove
  • pointerenter
  • pointerleave

For example:

const card = document.querySelector('.course-card');

card.addEventListener('pointerenter', () => {
    console.log('Pointer entered.');
});

Keyboard Events

Keyboard events allow JavaScript to respond when users interact with the keyboard.

The most commonly used keyboard events are:

  • keydown
  • keyup

Example:

document.addEventListener('keydown', (event) => {
    console.log(event.key);
});

If the user presses the letter A, the value of event.key will identify the key that was pressed.

event.code

The code property identifies the physical keyboard key.

document.addEventListener('keydown', (event) => {
    console.log(event.code);
});

This can be useful when building keyboard controls.

Checking for the Enter Key

document.addEventListener('keydown', (event) => {

    if (event.key === 'Enter') {
        console.log('Enter pressed.');
    }

});

Checking for the Escape Key

document.addEventListener('keydown', (event) => {

    if (event.key === 'Escape') {
        console.log('Escape pressed.');
    }

});

Input Events

The input event fires when the value of an input changes as the user types or otherwise edits it.

HTML:

<input id="student-name" type="text">

<p id="preview"></p>

JavaScript:

const input = document.querySelector('#student-name');

const preview = document.querySelector('#preview');

input.addEventListener('input', () => {
    preview.textContent = input.value;
});

The preview updates as the user types.

Reading Input Values

Form controls commonly expose their current value through the value property.

const emailInput = document.querySelector('#email');

console.log(emailInput.value);

Change Events

The change event is commonly used with select controls, checkboxes and other form elements.

Example:

const course = document.querySelector('#course');

course.addEventListener('change', () => {
    console.log(course.value);
});

Focus Events

The focus event occurs when an element receives focus.

const input = document.querySelector('#student-name');

input.addEventListener('focus', () => {
    console.log('Input focused.');
});

Blur Events

The blur event occurs when an element loses focus.

input.addEventListener('blur', () => {
    console.log('Input lost focus.');
});

Form Submit Events

Forms are especially important in web development.

HTML:

<form id="registration-form">

    <input
        id="student-name"
        type="text"
        required
    >

    <button type="submit">
        Register
    </button>

</form>

JavaScript:

const form = document.querySelector('#registration-form');

form.addEventListener('submit', (event) => {

    console.log('Form submitted.');

});

preventDefault()

By default, submitting an HTML form can cause the browser to perform its normal form submission behavior.

JavaScript can prevent that default behavior using preventDefault().

form.addEventListener('submit', (event) => {

    event.preventDefault();

    console.log('Default form submission prevented.');

});

This is commonly used when JavaScript needs to validate or process the form before sending information elsewhere.

Simple Form Processing

const form = document.querySelector('#registration-form');

const nameInput =
    document.querySelector('#student-name');

form.addEventListener('submit', (event) => {

    event.preventDefault();

    const name = nameInput.value.trim();

    if (!name) {
        console.log('Name is required.');
        return;
    }

    console.log(`Welcome, ${name}!`);

});

This example combines events, input values, strings and conditional logic.

Event Listeners and Multiple Actions

An element can have more than one event listener.

button.addEventListener('click', () => {
    console.log('Action 1');
});

button.addEventListener('click', () => {
    console.log('Action 2');
});

Both handlers can respond to the same event.

Removing Event Listeners

You can remove an event listener using removeEventListener().

The function reference must be the same function that was originally registered.

function handleClick() {
    console.log('Clicked.');
}

button.addEventListener('click', handleClick);

button.removeEventListener('click', handleClick);

After removal, that listener will no longer respond to clicks.

Why Function References Matter

This does not work as intended:

button.addEventListener('click', () => {
    console.log('Clicked.');
});

button.removeEventListener('click', () => {
    console.log('Clicked.');
});

The two arrow functions are different function objects.

For reliable removal, use a named function:

function handleClick() {
    console.log('Clicked.');
}

button.addEventListener('click', handleClick);

button.removeEventListener('click', handleClick);

Event Bubbling

Events can propagate through the DOM.

Consider:

<div class="card">
    <button>Open</button>
</div>

If the button is clicked, the click event can first occur on the button and then propagate upward through its ancestors.

This behavior is known as event bubbling.

Demonstrating Bubbling

const card = document.querySelector('.card');

const button = card.querySelector('button');

card.addEventListener('click', () => {
    console.log('Card clicked.');
});

button.addEventListener('click', () => {
    console.log('Button clicked.');
});

Clicking the button can cause both handlers to execute because the event bubbles from the button toward the card.

stopPropagation()

The stopPropagation() method prevents the event from continuing through the propagation path.

button.addEventListener('click', (event) => {

    event.stopPropagation();

    console.log('Button clicked.');

});

This should be used intentionally rather than as a general solution to event-related problems.

Event Delegation

Event delegation is a technique where an event listener is placed on a parent element instead of attaching separate listeners to every child.

Consider a course list:

<ul id="course-list">

    <li>
        <button class="course-button">
            Web Development
        </button>
    </li>

    <li>
        <button class="course-button">
            Data Analysis
        </button>
    </li>

</ul>

Instead of attaching listeners to every button, attach one listener to the list.

const courseList =
    document.querySelector('#course-list');

courseList.addEventListener('click', (event) => {

    if (event.target.matches('.course-button')) {
        console.log(event.target.textContent);
    }

});

This is particularly useful for dynamically generated content.

Why Event Delegation Is Useful

Event delegation can reduce the number of event listeners required and can allow newly added matching elements to work without attaching a new listener individually.

This makes it useful for:

  • Dynamic lists.
  • Tables.
  • Course cards.
  • Navigation menus.
  • Notifications.
  • Task lists.

Using closest()

Sometimes the user clicks an element inside the actual button or component.

For example:

<button class="course-button">
    <span>Web Development</span>
</button>

If the user clicks the span, event.target may refer to the span rather than the button.

You can find the nearest matching ancestor using closest().

courseList.addEventListener('click', (event) => {

    const button =
        event.target.closest('.course-button');

    if (!button) {
        return;
    }

    console.log(button.textContent);

});

Mouse Position

Some pointer and mouse events provide coordinate information.

document.addEventListener('mousemove', (event) => {

    console.log(event.clientX);
    console.log(event.clientY);

});

These values can be used when building interfaces involving pointer movement.

Keyboard Shortcuts

JavaScript can respond to combinations of keys.

document.addEventListener('keydown', (event) => {

    if (event.ctrlKey && event.key === 's') {
        event.preventDefault();

        console.log('Custom save action.');
    }

});

Keyboard combinations should be designed carefully so that they do not unnecessarily interfere with normal browser or operating-system behavior.

One-Time Event Listeners

The addEventListener() method accepts an options object.

For example, a listener can be configured to run only once:

button.addEventListener(
    'click',
    () => {
        console.log('This runs once.');
    },
    {
        once: true
    }
);

After the first matching event, the browser removes that listener.

Passive Event Listeners

Some events can also use the passive option.

element.addEventListener(
    'touchstart',
    handleTouch,
    {
        passive: true
    }
);

Passive listeners communicate that the handler will not call preventDefault(). This can help browsers optimize certain input interactions.

Event Listener Options

Common event listener options include:

  • once — automatically removes the listener after it runs.
  • passive — indicates that the listener will not call preventDefault().
  • capture — controls whether the listener participates in the capture phase.

Event Capture

Event propagation has phases. A simplified model is:

Capture
   ↓
Target
   ↓
Bubble

Most event listeners are commonly used during the bubbling phase.

You can register a listener during the capture phase using:

element.addEventListener(
    'click',
    handleClick,
    {
        capture: true
    }
);

Understanding capture and bubbling becomes increasingly important when building complex interfaces.

Dynamic Content and Events

A common problem occurs when JavaScript creates new elements after the page has loaded.

For example:

const button = document.createElement('button');

button.textContent = 'New Course';

courseList.append(button);

If event listeners were attached only to elements that existed when the script initially ran, the new button may not have those listeners.

Event delegation can solve this problem by placing the listener on a stable parent element.

Practical LMS Example

Imagine an LMS with several lesson buttons.

<div id="lesson-list">

    <button
        class="lesson-button"
        data-lesson-id="1"
    >
        Lesson 1
    </button>

    <button
        class="lesson-button"
        data-lesson-id="2"
    >
        Lesson 2
    </button>

</div>

JavaScript:

const lessonList =
    document.querySelector('#lesson-list');

lessonList.addEventListener('click', (event) => {

    const button =
        event.target.closest('.lesson-button');

    if (!button) {
        return;
    }

    const lessonId =
        button.dataset.lessonId;

    console.log(`Opening lesson ${lessonId}`);
});

This approach can be used as the foundation for interactive lesson navigation.

Practical Student Dashboard Example

HTML:

<button id="toggle-menu">
    Menu
</button>

<nav id="student-menu" class="hidden">
    <a href="/student-dashboard/">
        Dashboard
    </a>

    <a href="/courses/">
        Courses
    </a>
</nav>

JavaScript:

const toggleButton =
    document.querySelector('#toggle-menu');

const menu =
    document.querySelector('#student-menu');

toggleButton.addEventListener('click', () => {

    menu.classList.toggle('hidden');

});

This simple pattern forms the foundation of many mobile navigation systems.

Practical Form Validation Example

const form =
    document.querySelector('#student-form');

const email =
    document.querySelector('#email');

form.addEventListener('submit', (event) => {

    event.preventDefault();

    if (!email.value.trim()) {
        console.log('Email is required.');
        return;
    }

    console.log('Form ready for processing.');

});

Later lessons can extend this pattern with more advanced validation and asynchronous requests.

Common Event Handling Mistakes

1. Calling the Handler Immediately

Incorrect:

button.addEventListener('click', handleClick());

Correct:

button.addEventListener('click', handleClick);

2. Selecting an Element That Does Not Exist

const button = document.querySelector('#missing');

button.addEventListener('click', handleClick);

If button is null, this causes an error.

Safer:

const button = document.querySelector('#save-button');

if (button) {
    button.addEventListener('click', handleClick);
}

3. Forgetting preventDefault()

When creating custom JavaScript form handling, remember that the browser still has its normal form behavior.

form.addEventListener('submit', (event) => {

    event.preventDefault();

    // Custom processing.

});

4. Adding Too Many Listeners

When a page contains many repeated elements, event delegation can sometimes provide a cleaner architecture.

5. Misusing stopPropagation()

Stopping propagation can hide the underlying event-flow problem. Use it only when the interface genuinely requires propagation to stop.

Event Handling Best Practices

  • Prefer addEventListener() over inline HTML event attributes.
  • Use meaningful handler function names.
  • Keep event handlers focused on one responsibility.
  • Check that elements exist before attaching listeners when necessary.
  • Use preventDefault() when intentionally replacing default browser behavior.
  • Use event delegation for suitable dynamic collections.
  • Avoid unnecessary use of stopPropagation().
  • Remove listeners when they are no longer required and you have retained the correct function reference.
  • Use event.target and event.currentTarget appropriately.
  • Keep interaction logic separate from presentation styles.

Mini Practical Project

Create an interactive course progress panel.

HTML:

<section id="course-panel">

    <h2>JavaScript Fundamentals</h2>

    <p id="progress">
        Progress: 0%
    </p>

    <button id="complete-lesson">
        Complete Lesson
    </button>

</section>

JavaScript:

const button =
    document.querySelector('#complete-lesson');

const progress =
    document.querySelector('#progress');

let percentage = 0;

button.addEventListener('click', () => {

    percentage += 10;

    if (percentage > 100) {
        percentage = 100;
    }

    progress.textContent =
        `Progress: ${percentage}%`;

});

This project combines variables, conditionals, DOM manipulation and event handling.

Improving the Project

You can change the button after the course reaches 100%.

button.addEventListener('click', () => {

    percentage += 10;

    if (percentage >= 100) {
        percentage = 100;

        button.textContent = 'Course Complete';

        button.disabled = true;
    }

    progress.textContent =
        `Progress: ${percentage}%`;

});

This demonstrates how event handling can create interactive application behavior.

Summary

Events allow JavaScript applications to respond to actions and changes occurring in the browser.

You learned how to:

  • Understand browser events.
  • Attach handlers with addEventListener().
  • Handle click events.
  • Handle keyboard events.
  • Handle input and change events.
  • Handle form submission.
  • Use the Event object.
  • Use target and currentTarget.
  • Prevent default browser behavior.
  • Understand event bubbling and capture.
  • Use event delegation.
  • Remove event listeners.
  • Build interactive LMS components.

Event handling connects JavaScript logic to real user interaction. In the next lesson, these concepts will be applied to forms, validation and user input.

💻

Code Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScript Event Handling</title>

    <style>
        .completed {
            text-decoration: line-through;
            opacity: 0.6;
        }

        .message {
            margin-top: 15px;
        }
    </style>
</head>
<body>

    <h1 id="course-title">
        JavaScript Fundamentals
    </h1>

    <p id="progress">
        Progress: 0%
    </p>

    <button id="complete-lesson">
        Complete Lesson
    </button>

    <p id="message" class="message"></p>

    <form id="student-form">

        <label for="student-name">
            Student Name
        </label>

        <input
            id="student-name"
            type="text"
            required
        >

        <button type="submit">
            Continue
        </button>

    </form>

    <script>
        const completeButton =
            document.querySelector('#complete-lesson');

        const progress =
            document.querySelector('#progress');

        const message =
            document.querySelector('#message');

        const form =
            document.querySelector('#student-form');

        const studentName =
            document.querySelector('#student-name');

        let percentage = 0;

        completeButton.addEventListener('click', () => {

            percentage += 10;

            if (percentage >= 100) {
                percentage = 100;

                completeButton.textContent =
                    'Course Complete';

                completeButton.disabled = true;

                message.textContent =
                    'Congratulations! Course completed.';

                message.classList.add('completed');
            }

            progress.textContent =
                `Progress: ${percentage}%`;
        });

        studentName.addEventListener('input', () => {

            message.textContent =
                `Hello, ${studentName.value}`;
        });

        form.addEventListener('submit', (event) => {

            event.preventDefault();

            const name =
                studentName.value.trim();

            if (!name) {
                return;
            }

            message.textContent =
                `Welcome, ${name}!`;
        });
    </script>

</body>
</html>
⭐

Key Takeaways

["Events are occurrences detected by the browser, such as clicks, typing and form submissions.","Event handlers are functions that execute in response to events.","addEventListener() is the standard way to attach JavaScript event listeners.","The Event object provides information about the event that occurred.","event.target identifies the originating event target.","event.currentTarget identifies the element whose listener is currently running.","preventDefault() prevents an event from performing its normal browser action.","Events can propagate through the DOM using capture and bubbling phases.","stopPropagation() should be used intentionally when propagation genuinely needs to stop.","Event delegation allows a parent element to handle events from suitable child elements.","removeEventListener() requires the same function reference used when registering the listener.","Input, keyboard, mouse, pointer and form events are fundamental to interactive web applications.","Good event architecture keeps interaction logic organized and maintainable."]

Enjoying this lesson?

Sign in to your Dwallnet Academy student account to track your learning progress and mark lessons as complete.

Sign In to Track Progress