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.

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.cssandlayout.cssin a folder calledevent-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.
- 01How the page runs your scriptIn the workbook · 1 exercise
Add one script to the event page, see when it runs, and meet the tree it works on.
- 02Events and delegationIn the workbook · 1 exercise
Make the buttons do something, with one listener that hears every card.
- 03State in, HTML out, safelyIn the workbook · 1 exercise
Keep what the page knows in one object, draw the page from it, and never let text become code.
- 04Forms: validation, focus and status messagesIn the workbook · 1 exercise
Check the sign-up form in the browser, send nothing, and tell every user what happened.
- 05Saving state, and reading errorsIn the workbook · 1 exercise
Keep the shortlist after a reload, know what localStorage is not for, and read what the Console tells you.
- 06Reviewing JavaScript an assistant writesIn the workbook · 1 exercise
Run code you did not write before you trust it, and know the faults to look for.
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
scriptattribute 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.
- The Script element: script (defer, async and module scripts)MDN Web Docs
- JavaScript modulesMDN Web Docs
- Document Object Model (DOM)MDN Web Docs
- Document: querySelector() methodMDN Web Docs
- Document: querySelectorAll() methodMDN Web Docs
- HTMLElement: dataset propertyMDN Web Docs
- constMDN Web Docs
- Arrow function expressionsMDN Web Docs
- EventTarget: addEventListener() methodMDN Web Docs
- Event bubbling (including event delegation)MDN Web Docs
- Event: currentTarget propertyMDN Web Docs
- Element: closest() methodMDN Web Docs
- Node: cloneNode() methodMDN Web Docs
- Event: preventDefault() methodMDN Web Docs
- HTMLFormElement: submit eventMDN Web Docs
- Keyboard-navigable JavaScript widgetsMDN Web Docs
- Node: textContent propertyMDN Web Docs
- Element: innerHTML property (security considerations)MDN Web Docs
- Cross-site scripting (XSS)MDN Web Docs
- Using HTML form validation and the Constraint Validation APIMDN Web Docs
- ValidityStateMDN Web Docs
- HTMLInputElement: checkValidity() methodMDN Web Docs
- HTMLInputElement: setCustomValidity() methodMDN Web Docs
- Client-side form validationMDN Web Docs
- HTMLElement: focus() methodMDN Web Docs
- ARIA live regionsMDN Web Docs
- ARIA: status roleMDN Web Docs
- Window: localStorage propertyMDN Web Docs
- Storage quotas and eviction criteriaMDN Web Docs
- JSON.parse()MDN Web Docs
- TypeError: "x" is (not) "y"MDN Web Docs
- ReferenceError: "x" is not definedMDN Web Docs
- HTML Standard: Scripting (the script element)WHATWG
- HTML Standard: Web storageWHATWG
- HTML Standard: Form control infrastructure (constraints and novalidate)WHATWG
- HTML Standard: The input element (valid email address)WHATWG
- DOM Standard (events and textContent)WHATWG
- ECMAScript Language Specification, editor's draft: The JSON Object (JSON.parse)Ecma International, TC39
- ECMAScript Language Specification, editor's draft: Let and Const DeclarationsEcma International, TC39
- Web Content Accessibility Guidelines (WCAG) 2.2W3C
- Understanding Success Criterion 2.1.1: KeyboardW3C Web Accessibility Initiative
- Understanding Success Criterion 3.3.1: Error IdentificationW3C Web Accessibility Initiative
- Understanding Success Criterion 3.3.3: Error SuggestionW3C Web Accessibility Initiative
- Understanding Success Criterion 4.1.3: Status MessagesW3C Web Accessibility Initiative
- ARIA21: Using aria-invalid to Indicate An Error FieldW3C Web Accessibility Initiative
- ARIA22: Using role=status to present status messagesW3C Web Accessibility Initiative
- Button Pattern (WAI-ARIA Authoring Practices Guide)W3C Web Accessibility Initiative
- Fix JavaScript errors that are reported in the ConsoleMicrosoft Learn, Microsoft Edge developer documentation
- Console overviewMicrosoft Learn, Microsoft Edge developer documentation
- 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
Recommended for you
Host a chatbot on your website, safely
Put a chatbot on your site without leaking keys or running up bills: server function, limits, CORS, privacy, accessibility, fallbacks, monitoring and a launch checklist.
Recommended for you
Build and launch a website with AI
Plan a simple site, have AI write the HTML and CSS, understand and check the code, then publish it free with HTTPS and sound search, accessibility and privacy basics.