Essential storage keeps sign-in and learning features working. Google Analytics measures visits; Microsoft Clarity records interactions to help us improve usability. Both are optional and stay off until you choose. Read our privacy policy.
Design an accessible, privacy-conscious registration flow, then audit its failure states.
3–5 hours · Free project pack
A neighborhood library is opening a free repair workshop. People register on shared phones, use keyboards or screen readers, and may not want to disclose personal information. Build a registration page and a separate, static error-state specimen. Your deliverable is the HTML contract a backend team could implement—not a pretend working booking service.
A label answers what a field means; a name determines the key in submitted form data. Those are different contracts. Optional text can contain sensitive information even when you did not request it.
List each control's name, type, required status, and the reason it exists. Describe who would receive the data, how long it should be retained, and what remains outside this static exercise.
A short field inventory and a decision explaining why at least two tempting fields were excluded.
Explicit labels enlarge the click target and provide accessible names. A fieldset groups related options, while a legend names that group. Placeholder text disappears during entry and cannot replace a persistent label.
Build the valid-entry specimen. Associate help with aria-describedby; use type=email and autocomplete tokens. Put required information in visible labels. Use radio inputs with the same name and distinct values.
Tab through the controls without a mouse. Activate the radio group using arrow keys. Record the sequence and confirm that every label focuses its control.
Native constraint validation helps with simple input rules but cannot know whether a session has filled. A server response must preserve non-sensitive input, explain what happened, and link errors to their controls. A static specimen does not need a live-region announcement for content already present at page load.
Create errors.html with an error summary linking to the email field, a specific inline error, aria-invalid=true on that field, and the error ID included in aria-describedby. Keep the session selection intact.
Follow the summary link using a keyboard and inspect the accessibility tree. Explain the difference between syntax validation and a business-rule check such as session capacity.
HTML constraints are convenience checks, not a security boundary. Real processing needs server validation, request-forgery protection, length limits, abuse controls, and an honest retention policy. An example cannot truthfully promise a booking or an email.
Keep the submit button disabled with a visible explanation in both specimens. Write the backend handoff: accepted field names, error response behavior, success behavior, and consent/retention questions for the service owner.
Confirm no real POST occurs in the prototype. Demonstrate a blank email, malformed email, long note, and unavailable session as separate test cases.
A validator cannot decide whether an error message is helpful or a field is necessary. Your review should combine structural checks with human tasks.
Review both files against the rubric below. Write one remaining limitation, one rejected alternative, and a focused question for a human reviewer. A reference solution is a design to critique, not a pixel target.
Two HTML files, the field inventory, keyboard test notes, and a self-review.
This rubric supports a self-review or a human review. It is not a verified certificate or an automated pass.
Download each file into the same folder. Keep your working copy locally; these starter downloads never overwrite your saved course work.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Repair workshop registration</title>
</head>
<body>
<!-- Build a labeled form and document its data contract. -->
</body>
</html>Try your own design first. Then compare the decisions, not just the markup.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Register · Library repair workshop</title>
</head>
<body>
<header><a href="#main">Skip to registration</a><p>Library repair workshop</p></header>
<main id="main"><h1>Register for a repair workshop</h1>
<p id="demo">Learning prototype: no registration is sent or stored here.</p>
<form action="/workshop/registrations" method="post" aria-describedby="demo">
<p><label for="full-name">Name (required)</label><br><input id="full-name" name="full_name" autocomplete="name" maxlength="100" required></p>
<p><label for="email">Email (required)</label><br><input id="email" name="email" type="email" autocomplete="email" maxlength="254" aria-describedby="email-help" required></p>
<p id="email-help">A real service would use this address for workshop updates. No email is sent in this prototype.</p>
<fieldset><legend>Session (required)</legend>
<p><input id="morning" name="session" type="radio" value="morning" required><label for="morning">Morning, 10:00–12:00</label></p>
<p><input id="afternoon" name="session" type="radio" value="afternoon"><label for="afternoon">Afternoon, 14:00–16:00</label></p>
</fieldset>
<p><label for="access">Access needs (optional)</label><br><textarea id="access" name="access_notes" maxlength="500" aria-describedby="access-help"></textarea></p>
<p id="access-help">Describe practical assistance, such as step-free access. Do not include medical history or sensitive personal details.</p>
<button type="submit" disabled>Registration unavailable in this prototype</button>
</form>
<p><a href="errors.html">Inspect an example failed-validation response</a></p>
</main></body></html><!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Correct your email · Library repair workshop</title>
</head>
<body>
<main><h1>Check your registration</h1>
<section aria-labelledby="error-title"><h2 id="error-title">There is one problem</h2>
<ul><li><a href="#email">Enter an email address with a domain, such as learner@example.test.</a></li></ul></section>
<p id="demo">Static error-state specimen. No data is submitted.</p>
<form action="/workshop/registrations" method="post" aria-describedby="demo">
<p><label for="name">Name (required)</label><br><input id="name" name="full_name" value="Example Learner" autocomplete="name" maxlength="100" required></p>
<p><label for="email">Email (required)</label><br><input id="email" name="email" type="email" value="learner@" autocomplete="email" maxlength="254" required aria-invalid="true" aria-describedby="email-help email-error"></p>
<p id="email-help">Used for workshop updates in the real service.</p>
<p id="email-error">Enter a complete address, such as learner@example.test.</p>
<fieldset><legend>Session (required)</legend>
<p><input id="morning" name="session" type="radio" value="morning" required checked><label for="morning">Morning, 10:00–12:00</label></p>
<p><input id="afternoon" name="session" type="radio" value="afternoon"><label for="afternoon">Afternoon, 14:00–16:00</label></p>
</fieldset>
<p><label for="access">Access needs (optional)</label><br><textarea id="access" name="access_notes" maxlength="500" aria-describedby="access-help"></textarea></p>
<p id="access-help">Describe practical assistance only; omit sensitive medical details.</p>
<button type="submit" disabled>Registration unavailable in this prototype</button>
</form><p><a href="register.html">Return to the blank registration specimen</a></p>
</main></body></html>