Browser Reactivity

Adding client-side interactivity

Concepts

What Alpine.js is

Including Alpine.js

Showing and hiding a details panel

A confirmation dialog

Reviewing the generated JavaScript

Check for Understanding

What is the difference between client-side and server-side code, and which one runs after the page loads without a network request?

Client-side code (JavaScript in the browser) runs on the user's machine after the page has loaded; it can modify what the user sees instantly without contacting the server. Server-side code runs on the server and produces a response; the browser must make an HTTP request to trigger it. Client-side code runs without a network request; server-side code always requires one.

What does x-data="{ open: false }" do, and how does x-show="open" use it?

x-data attaches a reactive state object { open: false } to the element and all its children. x-show="open" evaluates the expression open against that state and hides the element (sets display: none) when it is falsy. When open is set to true (e.g., by clicking a button with @click="open = true"), Alpine.js removes the hidden style and the element becomes visible—without any page reload.

Why is a client-side "are you sure?" dialog not a sufficient security check for a destructive action?

The dialog runs JavaScript in the browser, which the user controls. A technically sophisticated user can open the browser console, call the delete endpoint directly with fetch(), or craft an HTTP request with curl, bypassing the dialog entirely. Security checks must happen on the server, where they cannot be bypassed by the client.

What does "declarative" mean in the context of Alpine.js, and how does it differ from writing document.getElementById(...).style.display = 'none'?

Declarative code describes the desired state: "this element is visible when open is true." Alpine.js works out how to make that true. Imperative code (getElementById followed by style.display = 'none') describes the steps: find the element and then change a property. Declarative code is usually easier to read because it says what, not how, and the framework keeps the UI consistent with the state automatically.

Exercises

Add a collapsible section

Use Alpine.js to add a toggle button to each table row that shows and hides a "technical details" panel below the row containing fields like measurement ID, data entry date, and observer name. The panel should be hidden by default. Prompt the LLM to write the Alpine.js markup, then read each attribute and explain what it does.

Live character count

Add a notes field to the data-entry form and use Alpine.js to display a live character count below the input that updates as the user types. Show the count as "12/200 characters" where 200 is the maximum allowed length. Implement it yourself first, then compare to what the LLM produces.

Sort without a reload

Prompt the LLM to use Alpine.js to sort the visible table rows by clicking a column header without making a server request. What are the limitations of sorting data already in the browser versus sorting in SQL?

Audit the generated JavaScript

Prompt the LLM to explain, attribute by attribute, every piece of Alpine.js syntax it generated for this lesson. Write a one-sentence correction for any explanation you disagree with.