Skip to Content
Lab 2 (AI)

Interactive Registration Form with a Socratic Tutor

In this lab, you will build an interactive user registration form with real-time validation and localStorage persistence, and then use Claude as a strict Socratic tutor to deepen your understanding of how the events in your own code travel through the browser.

Estimated Time: 2.5 hours, asynchronous (approximately 1 hour 45 minutes for Part A and 30 to 45 minutes for Part B).


Workplace Context

Imagine you are a junior front-end developer at a startup. Your team is building a new web application, and your first task is to create the client-side functionality for the user registration page. It is crucial that this form is user-friendly, provides clear validation feedback to prevent errors, and remembers some basic user input for convenience. After you ship a feature, your tech lead also expects you to explain how it works in a code review: not just what the code does, but how the browser processes each event behind the scenes. This lab simulates both parts of that job. You will build the form, and then you will prove your understanding of its event handling by teaching it back during a question-driven session with an AI tutor.


Objectives

By the end of this lab, you will be able to:

  1. Structure an HTML form with appropriate input fields for registration.
  2. Implement real-time input validation using JavaScript event listeners (input event).
  3. Use HTML5 validation attributes (e.g., required, type, minlength, pattern).
  4. Apply the JavaScript Constraint Validation API to check validity and display custom error messages.
  5. Dynamically create and display error messages next to input fields.
  6. Handle the form submit event, prevent default submission, and perform final validation.
  7. Use localStorage to save and retrieve simple form data (e.g., username).
  8. Formulate prompts that direct an AI assistant to act strictly as a Socratic tutor.
  9. Explain, in your own words, the capture, target, and bubble phases that each event in your code travels through, from the browser window down to the target element and back.

Part A: Build the Registration Form

Part A is the same build as the standard version of this lab. Complete it entirely yourself, without AI assistance. Part B depends on the code being your own: you cannot explain code you did not write, and your Socratic tutor will only ask questions about the listeners you implemented.

Step 1: Set Up the Project

  1. Create a new folder named interactive-registration-form.
  2. Inside this folder, create the following files:
    • index.html
    • styles.css
    • script.js
  3. Initialize the folder as a Git repository so you can commit your progress and push it to GitHub for submission:
cd interactive-registration-form git init

Step 2: Build the HTML Structure

Create the basic HTML structure for your registration form in index.html. Include fields for: Username, Email, Password, and Confirm Password. Also, add a submit button. Ensure each input has a corresponding <span> element for error messages.

We have included an example below, for convenience, but you will need to modify it to include validation attributes (such as required, minlength, and pattern) and any other elements you need.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="styles.css"> <title>Interactive Registration Form</title> </head> <body> <div class="container"> <h1>Register</h1> <form id="registrationForm" novalidate> <div class="form-group"> <label for="username">Username:</label> <input type="text" id="username" name="username"> <span class="error-message" id="usernameError"></span> </div> <div class="form-group"> <label for="email">Email:</label> <input type="email" id="email" name="email" required> <span class="error-message" id="emailError"></span> </div> <div class="form-group"> <label for="password">Password:</label> <input type="password" id="password" name="password"> <small>Password must be at least 8 characters long, include an uppercase letter, a lowercase letter, and a number.</small> <span class="error-message" id="passwordError"></span> </div> <div class="form-group"> <label for="confirmPassword">Confirm Password:</label> <input type="password" id="confirmPassword" name="confirmPassword"> <span class="error-message" id="confirmPasswordError"></span> </div> <button type="submit">Register</button> </form> </div> <script src="script.js"></script> </body> </html>

Step 3: Style the Application

Add some basic styles in styles.css to make the form presentable and to style the error messages. An example is provided below, for convenience, but you can modify it as you see fit.

body { font-family: Arial, sans-serif; background-color: #f4f4f4; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; } .container { background-color: #fff; padding: 20px 30px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); width: 400px; } h1 { text-align: center; color: #333; } .form-group { margin-bottom: 15px; } .form-group label { display: block; margin-bottom: 5px; font-weight: bold; } .form-group input[type="text"], .form-group input[type="email"], .form-group input[type="password"] { width: calc(100% - 22px); /* Account for padding and border */ padding: 10px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; /* Makes width calculation easier */ } .form-group input:invalid { border-color: #e74c3c; /* Light red for invalid built-in states */ } /* You can add a .valid class if you want to style valid inputs too */ .form-group .error-message { display: block; color: #e74c3c; /* Red for error messages */ font-size: 0.9em; margin-top: 5px; min-height: 1em; /* Reserve space to prevent layout shifts */ } .form-group small { display: block; font-size: 0.8em; color: #777; margin-top: 3px; } button[type="submit"] { width: 100%; padding: 10px; background-color: #3498db; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; } button[type="submit"]:hover { background-color: #2980b9; }

Step 4: Implement the JavaScript

In script.js, implement the core validation logic.

  1. Select all necessary DOM elements (form, inputs, error message spans).
  2. Load saved username: On page load, check if a username is saved in localStorage. If so, pre-fill the username field.
  3. Real-time validation: Add input event listeners to each field.
    • Check validity using the Constraint Validation API (inputElement.validity).
    • For the “Confirm Password” field, explicitly check if it matches the “Password” field.
    • Display appropriate custom error messages in the corresponding <span> elements. Clear messages if valid.
  4. Form submission: Add a submit event listener to the form.
    • Call event.preventDefault().
    • Perform a final validation check on all fields.
    • If all fields are valid:
      • Display a success message (e.g., an alert or update a status message on the page).
      • Save the username to localStorage.
      • Optionally, reset the form.
    • If any field is invalid, ensure error messages are displayed and focus on the first invalid field.

Ensure your JavaScript is well-commented. Commit your work as you complete each piece of functionality.


Step 5: Test and Validate

  1. Test Basic Registration: Fill out all fields with valid data and submit the form. Verify the success message and that the username is saved in localStorage (check your browser’s Developer Tools > Application > Local Storage).
  2. Test Username Validation:
    • Try submitting with an empty username.
    • Enter a username that is too short.
    • Verify error messages appear in real time as you type (or on blur/submit).
  3. Test Email Validation:
    • Try submitting with an empty email.
    • Enter an invalid email format (e.g., “test@”, “test.com”).
  4. Test Password Validation:
    • Try submitting with an empty password.
    • Enter a password that is too short.
    • Enter a password that does not meet the pattern (e.g., all lowercase, no numbers).
    • Ensure the “Confirm Password” field shows an error if it does not match the password.
  5. Test Local Storage Persistence: After a successful registration, refresh the page. The username field should be pre-filled with the value you entered.
  6. Edge Cases: Think about what happens if a user tries to bypass validation (client-side validation is mainly for UX; server-side validation is for security). What happens if localStorage is full or disabled? For this lab, we assume it works, but it is a real-world consideration.
Note

Checkpoint: Before moving on to Part B, your form must validate in real time as you type, block invalid submissions, show custom error messages, and pre-fill the username from localStorage after a refresh.


Part B: Socratic Tutor Session

You will now use Claude in the AI as Socratic Tutor role. In this role, the AI is explicitly forbidden from writing code or giving direct answers. It may only ask you guiding questions, and you supply every explanation yourself. The goal is for you to be able to trace, out loud and in writing, the exact path each event in your code travels: from the browser window, down through the document to the target element (the capture phase), through the target phase, and back up to the window (the bubble phase). This builds on the propagation phases you studied in Lesson 4. Note that the Lesson 4 diagrams begin the capture phase at document; the full path the browser dispatches actually begins one level higher, at the window object itself, and that is the path you will map in this lab.

Step 1: Set Up the Socratic Tutor Role

Give Claude the following role prompt, exactly as written, before any other message:

You are my Socratic tutor for DOM events. You must not write, complete, or correct any code, and you must not state final answers. Respond only with one guiding question at a time. When my explanation is accurate, confirm it briefly and ask a deeper question. If I ask you for the answer, decline and rephrase your question.

Choose one of the following setups:

Option 1: claude.ai (recommended)

  1. Sign in at https://claude.ai  with your Per Scholas-provided Claude Pro account.
  2. Create a new Project and paste the role prompt above into the Project’s custom instructions. This is the most reliable way to enforce the role, because the instructions apply to every conversation inside that Project. If you prefer not to use a Project, start a new chat and send the role prompt as your very first message instead.
  3. Paste the relevant portion of your script.js into the chat when a prompt refers to it, so the dialogue is grounded in your actual code.

Option 2: Claude Code (terminal)

  1. If you have not installed Claude Code yet, run npm install -g @anthropic-ai/claude-code (Node.js 18 or later is required, which you already have).
  2. Open a terminal in your interactive-registration-form folder and run claude. Log in with your Per Scholas-provided Claude account if prompted (/login).
  3. Paste the role prompt as your first message. Because Claude Code can read your files directly, you can then ground the dialogue in your real code, for example: “Read script.js. Using only questions, tutor me on the submit listener defined there.”
  4. Claude Code asks permission before editing files or running commands. In this lab it should never need to do either; if it proposes a file edit, decline it. The tutor asks questions, nothing more.
Note

If you do not have access to a Pro-level Claude account through Per Scholas, you may complete this lab using the free tier of Claude or another AI assistant with equivalent capabilities. Free-tier usage limits may require you to complete the lab across more than one session. The Socratic dialogues in this lab are short, so the free tier of claude.ai is normally sufficient; use the same role prompt as your first message in a regular chat.


Step 2: Formulate Your Three Socratic Prompts

This step is the core of the lab, so do it carefully and before you start any dialogue. You will write three prompts, one for each of the following listeners in your own script.js:

  1. The input event listener on the email field.
  2. The submit event listener on the form, including your use of event.preventDefault().
  3. One listener of your choice: a blur listener or a change listener if your implementation includes one, or the input listener that performs your confirm-password match check (every implementation from Part A includes this one).

Each prompt must:

  • Name the exact event type and element the listener is attached to (for example, “the input listener on the element with the id email”).
  • Direct the tutor to lead you, through questions only, to explain:
    • What user action dispatches the event.
    • The capture path the event travels from window, through document and every ancestor element of the target in your HTML, down to the target element.
    • What happens during the target phase.
    • The bubble path the event travels back up to window.
    • Which default browser behavior is involved, and what your code does about it (this matters most for the submit listener).

Here is a worked example for the email field. Do not copy it word for word; adapt it to your own code, and write your other two prompts yourself:

My script.js attaches an input event listener to the email field, the input element with the id "email", inside the form with the id "registrationForm". Acting only as my Socratic tutor, ask me one question at a time to lead me to explain: what user action dispatches the input event, the capture path the event travels from the window down through the document and my page structure to the email input, what happens during the target phase, the bubble path the event travels back up to the window, and how my validation logic runs as part of that journey. Do not explain anything yourself and do not show any code. Only ask questions.

A well-formed Socratic prompt meets all four points of this checklist:

CheckQuestion to ask yourself
Names the listenerDoes the prompt state the exact event type (input, submit, blur, change)?
Names the elementDoes the prompt identify the specific element by id or role in your HTML?
Constrains the AIDoes the prompt restrict the AI to questions only, with no code and no answers?
Targets the windowDoes the prompt require the full propagation path, from window to the target and back, plus the default browser behavior involved?

Record all three prompts in a new file named SOCRATIC-DIALOGUE.md in your project folder before you begin.

Note

Checkpoint: All three prompts are written down in SOCRATIC-DIALOGUE.md before you start any dialogue. Grading requires the prompts to appear verbatim, exactly as you sent them.


Step 3: Run the Dialogues

Run one dialogue per prompt, in order.

  1. Send your prompt to the tutor.
  2. Answer every question in your own words. Look at your own script.js and index.html while you answer; the point is to connect the concepts to your actual code.
  3. Do not ask the tutor for answers, hints phrased as answers, or code. If you get stuck, say what you think is true and let the next question steer you.
  4. If the AI drifts into lecturing, explaining, or writing code, restate the role constraint: “Remember, you are my Socratic tutor. Do not explain or write code. Ask me your question again.” Recovering the role when the AI drifts is part of the skill this lab teaches.
  5. Continue each dialogue until you have explained, and the tutor has confirmed, the full propagation path and the default behavior for that listener. A focused dialogue usually takes 6 to 12 exchanges.
  6. Save the evidence: use the Share button in claude.ai to create a public link to the conversation, or copy the full transcript into SOCRATIC-DIALOGUE.md. If sharing is disabled in your workspace, or you used Claude Code, copy the transcript text instead.

Step 4: Map Each Event’s Path Through the Browser

After each dialogue, and without the AI’s help, produce two artifacts in SOCRATIC-DIALOGUE.md for that listener:

  1. An event-flow map (plain text or ASCII) showing the capture path from window down to the target, the target phase, and the bubble path back up. Trace your actual HTML structure: every element between <body> and the target appears on the path. Using the starter HTML, a map for the email listener would look like this:
CAPTURE PHASE (window down to target) window -> document -> html -> body -> div.container -> form#registrationForm -> div.form-group -> input#email TARGET PHASE input#email (my "input" listener runs here) BUBBLE PHASE (target back up to window) input#email -> div.form-group -> form#registrationForm -> div.container -> body -> html -> document -> window
  1. A written explanation of 3 to 5 sentences, in your own words, connecting the listener to browser window behavior. For example: for the submit listener, explain why the browser would navigate away from the page if event.preventDefault() were omitted, and where in the event’s journey your handler intercepts it; for an input listener, explain how event delegation in general relies on the bubble phase you just mapped.

Two accuracy notes for your maps:

  • The target of the submit event is the form element itself, not the button you clicked. Your second map should therefore end its capture path at form#registrationForm.
  • The blur event captures down to the target but does not bubble. If you chose blur as your third listener, your map should show the capture and target phases only, and your explanation should point out this difference. Let the tutor lead you to discover it.
Note

Checkpoint: SOCRATIC-DIALOGUE.md now contains three prompts, three dialogue transcripts (or shared conversation links), three event-flow maps, and three written explanations.


Reflection Questions

Include your answers to the following questions in your submission, within the README.md file:

  1. How did event.preventDefault() help in handling form submission?
  2. What is the difference between using HTML5 validation attributes and JavaScript-based validation? Why might you use both?
  3. Explain how you used localStorage to persist and retrieve the username. What are the limitations of localStorage for storing sensitive data?
  4. Describe a challenge you faced in implementing the real-time validation and how you solved it.
  5. How did you ensure that custom error messages were user-friendly and displayed at the appropriate times?
  6. Which of your three prompts best constrained the AI to the Socratic method, and why?
  7. What did the questioning process reveal about event propagation that reading documentation had not?

Submission Guidelines

Submit your project via a GitHub repository link using the Start Assignment link on Canvas, or as instructed by your facilitator. Your repository must contain:

  • index.html, styles.css, and script.js (the completed registration form).
  • README.md with your answers to all seven reflection questions.
  • SOCRATIC-DIALOGUE.md containing, for each of the three listeners: your prompt exactly as you sent it, the full dialogue transcript or a shared conversation link, your event-flow map, and your 3 to 5 sentence written explanation.

You may structure SOCRATIC-DIALOGUE.md like this:

# Socratic Dialogue: DOM Events ## 1. The input listener on the email field ### My Prompt ### Dialogue (transcript or shared link) ### Event-Flow Map ### My Explanation ## 2. The submit listener on the form ... ## 3. My chosen listener: <event type> on <element> ...

This lab is graded complete/incomplete. To receive a complete, your submission must satisfy every item on the facilitator checklist:

  1. All functional requirements of the registration form are met: real-time validation with input event listeners, HTML5 validation attributes, the Constraint Validation API with custom error messages, submit handling with event.preventDefault() and final validation, and username persistence with localStorage.
  2. SOCRATIC-DIALOGUE.md contains your three formulated Socratic prompts verbatim.
  3. The transcript or shared conversation link demonstrates a genuine Socratic exchange: the AI asked questions, you supplied the explanations, and the AI wrote no code.
  4. All three event-flow maps correctly show the capture, target, and bubble phases from window to the target element (with the blur exception noted if you chose that event).
  5. Each map is accompanied by a 3 to 5 sentence explanation in your own words connecting the listener to browser window behavior (for example, what happens to page navigation if event.preventDefault() is omitted).