web · Level 3

JavaScript: the browser, events and application state

Make the event page respond to people with plain JavaScript and no build step: events, one state object, a checked form and a saved shortlist, tested in a real browser.

By Mickarle Wagstaff-Irons - Micky Irons

  • Level 3Building
  • 140 min
  • 6 chapters
  • Free PDF, no account
The Pageweb / 03

Start with the essentials

The short answer

Load your script with defer, find elements with querySelector and listen for events with addEventListener, often once on a parent. Keep what the page knows in one plain object and redraw the page from it. Put untrusted text in with textContent, never innerHTML. Validate forms with the Constraint Validation API, move focus to the first error, announce results in a status region and never store secrets in localStorage.

What you will learn

  • You will be able to load a script with defer, say why a module needs a web server, and find and create elements in the DOM tree.
  • You will be able to handle clicks and key presses with one delegated listener, using real buttons so the keyboard works without extra code.
  • You will be able to keep state in one plain object, render the page from it without losing focus, and keep untrusted text out of innerHTML.
  • You will be able to check a form with the Constraint Validation API, move focus to the first error and announce results in a status region, naming WCAG 2.2 criteria 3.3.1 and 4.1.3.
  • You will be able to save state in localStorage safely, state its limits, and read errors in the Console.
  • You will be able to review JavaScript that an AI assistant wrote and find its common faults by running it.

Who it is for

People who have hand-written an accessible, styled page, such as the event page from the HTML and CSS workbooks, and now want it to respond to the people using it. You write plain JavaScript in a text editor and test it in a browser, with no framework and no build step.

Before you start

  • The HTML and CSS workbooks, or the finished Marigold Lane event page from them: index.html, style.css and layout.css in a folder called event-page. A plain text editor and a desktop browser with developer tools; the tool names here are Microsoft Edge's. No earlier JavaScript is needed, but you should be happy to type code exactly and read it slowly.

Keep learning

The complete workbook

This workbook adds behaviour to the Marigold Lane event page from the HTML and CSS workbooks, with plain JavaScript, no framework and no build step. You will add shortlist buttons, keep their state in one object, check the sign-up form with the Constraint Validation API, announce changes to assistive technology and save the shortlist in localStorage, testing each step in a real browser. You will also learn to read errors, keep untrusted text out of innerHTML and review JavaScript an AI assistant writes.

  1. 01
    How the page runs your script

    Add one script to the event page, see when it runs, and meet the tree it works on.

    In the workbook · 1 exercise
  2. 02
    Events and delegation

    Make the buttons do something, with one listener that hears every card.

    In the workbook · 1 exercise
  3. 03
    State in, HTML out, safely

    Keep what the page knows in one object, draw the page from it, and never let text become code.

    In the workbook · 1 exercise
  4. 04
    Forms: validation, focus and status messages

    Check the sign-up form in the browser, send nothing, and tell every user what happened.

    In the workbook · 1 exercise
  5. 05
    Saving state, and reading errors

    Keep the shortlist after a reload, know what localStorage is not for, and read what the Console tells you.

    In the workbook · 1 exercise
  6. 06
    Reviewing JavaScript an assistant writes

    Run code you did not write before you trust it, and know the faults to look for.

    In the workbook · 1 exercise

Also inside: a 10-point checklist, a glossary of 12 terms and 10 questions and answers to test yourself. 6 hands-on exercises, each with a worked answer at the back where the workbook gives one.

No login, no card, no account. Before the download we ask you to follow Mickai (two quick links). Free to download and use for personal learning, study groups and inside your own team. Please do not resell the workbooks or republish them as your own. Link people to trust-agent.ai instead.

Test yourself

Questions and answers

Where should I put my script tag?

In the head, with defer: <script src="app.js" defer></script>. The file loads while the page is read and runs once the page has been parsed, so every element exists. Without defer, a script in the head runs before the body exists: in this workbook's tests it found no stall cards, at first silently and later with a TypeError. A plain script at the end of body also works, because the elements above it already exist.

Why does my module script not load when I open the page from disk?

MDN says modules loaded from a file opened on disk meet CORS errors, because of module security requirements, and that you should test them through a server. Edge 153 blocked the module in this workbook's test and reported the page's origin as null. Serve the folder from a local web server on your own computer, or use a classic script with defer.

What is the difference between textContent and innerHTML?

textContent sets text: whatever you give it appears as characters, never as markup. innerHTML parses its string as HTML, so a string containing an image with an onerror handler runs that handler. MDN advises against innerHTML for text. Use textContent for anything a person typed and anything from storage, a web address or another site.

What is event delegation, and when should I use it?

Events bubble from the element where they start up through its ancestors, so one listener on a parent can handle clicks on all its children. Use event.target.closest(...) to find the child that matters. It suits lists and grids, keeps the number of listeners down and works for children added later, which listeners attached to each child would miss.

Do I need extra code for keyboard users?

Not if you use real controls. A button takes focus with Tab and fires its click event for Enter and Space, as the Authoring Practices ask of a button. A div with a click listener gets neither. Only custom widgets need tabindex and key handling of your own, and then you should follow the matching Authoring Practices pattern.

Why keep state in one object instead of reading it from the page?

Because the page is output. When one function changes the state and another draws the page from it, they cannot disagree, and you can inspect the state in the Console. Reading state back from button text or colours invites drift, and rebuilding elements to show new state can destroy the element that has keyboard focus.

When should I use role=status or aria-live?

For short messages that report results, progress or errors without moving focus, such as Shortlisted: Cuttings. WCAG 2.2 criterion 4.1.3 asks that such messages can be announced. role="status" is polite, so it waits until the user is idle. Put the empty region in the HTML from the start, and move focus instead when the user must act, as with a form error.

Is checking a form in the browser enough?

No. It helps people fix mistakes quickly, but MDN warns it is easy to bypass, so a real form's server must check everything again. type="email" only checks the shape of an address: the HTML standard accepts a@b. Write your own messages beside each field, and move focus to the first problem.

What should I never keep in localStorage?

Passwords, access tokens, keys and personal details. Any script on the same origin can read it, including code injected through an XSS flaw, and it has no expiry date. Keep it for small, harmless things such as a shortlist, stored as JSON, and wrap reads and writes in try and catch, because both can throw.

Can I trust JavaScript an AI assistant writes?

Treat it as a draft from a stranger. Run it on a copy with the Console open, press Tab through the page and try hostile input. Look for invented APIs, var globals, innerHTML with user text, listeners added again and again, and clickable divs. Never paste passwords, keys or other people's data into a prompt.

When you have finished

Get your certificate of completion

Type your name and download a certificate for this workbook as a PDF, ready to print or to add to LinkedIn. It is made on your own device, so your name is never sent to us. It is a self-declared certificate, not an accredited qualification.

Learn the language

Key terms

DOM
The Document Object Model: the browser's tree of objects for a page, which scripts read and change.
defer
A script attribute that loads the file while the page is read and runs it after the page has been parsed.
Module
A script loaded with type="module": deferred, in strict mode and with private top-level names. It needs a web server rather than a file opened from disk.
Event
Something that happens on the page, such as a click or a key press, which listeners can react to.
Event delegation
One listener on a parent that handles events bubbling up from its children, including children added later.
State
What the page knows at a given moment, kept in one plain object.

6 of the workbook's 12 terms. The complete glossary is in the workbook.

Follow the evidence

Sources and checks

Facts last checked: .

Examples in this workbook were run on: Microsoft Edge 153.0.4234.48 (system install, headless) driven by Playwright 1.59.0 for Python 3.12.10 on Windows 11 Pro, using real mouse clicks and key presses on pages opened from disk (file: URLs); Console lines evaluated through the Chrome DevTools Protocol in Console (REPL) mode; accessibility properties read through the same protocol; one module test served from 127.0.0.1 by Python's http.server; a persistent browser profile for the file: storage restart test. No screen reader was used. (2026-09-26).

These workbooks use AI assistance. See how the workbooks are made.

  1. The Script element: script (defer, async and module scripts)MDN Web Docs
  2. JavaScript modulesMDN Web Docs
  3. Document Object Model (DOM)MDN Web Docs
  4. Document: querySelector() methodMDN Web Docs
  5. Document: querySelectorAll() methodMDN Web Docs
  6. HTMLElement: dataset propertyMDN Web Docs
  7. constMDN Web Docs
  8. Arrow function expressionsMDN Web Docs
  9. EventTarget: addEventListener() methodMDN Web Docs
  10. Event bubbling (including event delegation)MDN Web Docs
  11. Event: currentTarget propertyMDN Web Docs
  12. Element: closest() methodMDN Web Docs
  13. Node: cloneNode() methodMDN Web Docs
  14. Event: preventDefault() methodMDN Web Docs
  15. HTMLFormElement: submit eventMDN Web Docs
  16. Keyboard-navigable JavaScript widgetsMDN Web Docs
  17. Node: textContent propertyMDN Web Docs
  18. Element: innerHTML property (security considerations)MDN Web Docs
  19. Cross-site scripting (XSS)MDN Web Docs
  20. Using HTML form validation and the Constraint Validation APIMDN Web Docs
  21. ValidityStateMDN Web Docs
  22. HTMLInputElement: checkValidity() methodMDN Web Docs
  23. HTMLInputElement: setCustomValidity() methodMDN Web Docs
  24. Client-side form validationMDN Web Docs
  25. HTMLElement: focus() methodMDN Web Docs
  26. ARIA live regionsMDN Web Docs
  27. ARIA: status roleMDN Web Docs
  28. Window: localStorage propertyMDN Web Docs
  29. Storage quotas and eviction criteriaMDN Web Docs
  30. JSON.parse()MDN Web Docs
  31. TypeError: "x" is (not) "y"MDN Web Docs
  32. ReferenceError: "x" is not definedMDN Web Docs
  33. HTML Standard: Scripting (the script element)WHATWG
  34. HTML Standard: Web storageWHATWG
  35. HTML Standard: Form control infrastructure (constraints and novalidate)WHATWG
  36. HTML Standard: The input element (valid email address)WHATWG
  37. DOM Standard (events and textContent)WHATWG
  38. ECMAScript Language Specification, editor's draft: The JSON Object (JSON.parse)Ecma International, TC39
  39. ECMAScript Language Specification, editor's draft: Let and Const DeclarationsEcma International, TC39
  40. Web Content Accessibility Guidelines (WCAG) 2.2W3C
  41. Understanding Success Criterion 2.1.1: KeyboardW3C Web Accessibility Initiative
  42. Understanding Success Criterion 3.3.1: Error IdentificationW3C Web Accessibility Initiative
  43. Understanding Success Criterion 3.3.3: Error SuggestionW3C Web Accessibility Initiative
  44. Understanding Success Criterion 4.1.3: Status MessagesW3C Web Accessibility Initiative
  45. ARIA21: Using aria-invalid to Indicate An Error FieldW3C Web Accessibility Initiative
  46. ARIA22: Using role=status to present status messagesW3C Web Accessibility Initiative
  47. Button Pattern (WAI-ARIA Authoring Practices Guide)W3C Web Accessibility Initiative
  48. Fix JavaScript errors that are reported in the ConsoleMicrosoft Learn, Microsoft Edge developer documentation
  49. Console overviewMicrosoft Learn, Microsoft Edge developer documentation
  50. Run JavaScript in the Console (Allow pasting into the Console)Microsoft Learn, Microsoft Edge developer documentation

Created by Mickarle Wagstaff-Irons - Micky Irons with the Mickai team. Published by Mickai LTD. Last updated 26 September 2026.

NextKeep going

Where to go next