{ "$schema": "../schemas/code-crispies-module-schema.json", "id": "html-forms-validation", "title": "Validation", "description": "Learn HTML5 built-in form validation attributes", "mode": "html", "difficulty": "intermediate", "lessons": [ { "id": "required-fields", "title": "Required Fields", "description": "The required attribute prevents form submission if the field is empty.

Add it to any input that must be filled:
<input type=\"text\" required>

The browser shows a validation message automatically.", "task": "Make both the name and email fields required by adding the required attribute.", "previewHTML": "", "previewBaseCSS": "body { font-family: system-ui; padding: 20px; } form { max-width: 350px; } label { display: block; margin-top: 15px; margin-bottom: 5px; } label:first-of-type { margin-top: 0; } input { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; } input:invalid { border-color: #d32f2f; } button { margin-top: 20px; padding: 10px 20px; background: #1976d2; color: white; border: none; border-radius: 4px; cursor: pointer; }", "sandboxCSS": "", "initialCode": "
\n \n \n \n \n \n \n \n
", "solution": "
\n \n \n \n \n \n \n \n
", "previewContainer": "preview-area", "validations": [ { "type": "attribute_value", "value": { "selector": "input[name='name']", "attr": "required", "value": true }, "message": "Add the required attribute to the name input" }, { "type": "attribute_value", "value": { "selector": "input[name='email']", "attr": "required", "value": true }, "message": "Add the required attribute to the email input" } ] }, { "id": "input-constraints", "title": "Constraints", "description": "Control what users can enter:

minlength / maxlength - Text length limits
min / max - Number range
pattern - Regex pattern matching
placeholder - Hint text (not a label!)", "task": "Add validation to the password input:
1. Add minlength=\"8\" for minimum length
2. Add maxlength=\"20\" for maximum length
3. Add placeholder=\"Enter password\" as a hint", "previewHTML": "", "previewBaseCSS": "body { font-family: system-ui; padding: 20px; } form { max-width: 350px; } label { display: block; margin-bottom: 5px; } input { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; } input:invalid:not(:placeholder-shown) { border-color: #d32f2f; } small { display: block; font-size: 12px; color: #666; margin-top: 4px; } button { margin-top: 20px; padding: 10px 20px; background: #1976d2; color: white; border: none; border-radius: 4px; cursor: pointer; }", "sandboxCSS": "", "initialCode": "
\n \n \n Must be 8-20 characters\n \n \n
", "solution": "
\n \n \n Must be 8-20 characters\n \n \n
", "previewContainer": "preview-area", "validations": [ { "type": "attribute_value", "value": { "selector": "input[type='password']", "attr": "minlength", "value": "8" }, "message": "Add minlength=\"8\" to the password input" }, { "type": "attribute_value", "value": { "selector": "input[type='password']", "attr": "maxlength", "value": "20" }, "message": "Add maxlength=\"20\" to the password input" }, { "type": "attribute_value", "value": { "selector": "input[type='password']", "attr": "placeholder", "value": null }, "message": "Add a placeholder to hint what to enter" } ] }, { "id": "complete-registration", "title": "Full Form", "description": "Build a complete registration form with all validation concepts:

- Required fields marked with *
- Email validation (use type=\"email\")
- Password with length constraints
- Terms checkbox (required)
- Submit button", "task": "Complete the registration form. Add required attributes, proper input types, and validation constraints.", "previewHTML": "", "previewBaseCSS": "body { font-family: system-ui; padding: 20px; } form { max-width: 400px; background: #f5f5f5; padding: 25px; border-radius: 8px; } h2 { margin-top: 0; margin-bottom: 20px; } label { display: block; margin-top: 15px; margin-bottom: 5px; font-weight: 500; } input[type='text'], input[type='email'], input[type='password'] { width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; font-size: 14px; } input:focus { outline: 2px solid #1976d2; border-color: transparent; } input[type='checkbox'] { width: auto; margin-right: 8px; vertical-align: middle; } label:has(input[type='checkbox']) { display: flex; align-items: center; font-weight: normal; } button { width: 100%; margin-top: 20px; padding: 12px; background: #1976d2; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: 500; } button:hover { background: #1565c0; }", "sandboxCSS": "", "initialCode": "
\n

Create Account

\n \n \n \n \n \n \n \n \n \n \n \n \n \n
", "solution": "
\n

Create Account

\n \n \n \n \n \n \n \n \n \n \n \n \n \n
", "previewContainer": "preview-area", "validations": [ { "type": "attribute_value", "value": { "selector": "#fullname", "attr": "required", "value": true }, "message": "Make the full name field required" }, { "type": "attribute_value", "value": { "selector": "#email", "attr": "type", "value": "email" }, "message": "Set the email input type=\"email\"" }, { "type": "attribute_value", "value": { "selector": "#email", "attr": "required", "value": true }, "message": "Make the email field required" }, { "type": "attribute_value", "value": { "selector": "#password", "attr": "type", "value": "password" }, "message": "Set the password input type=\"password\"" }, { "type": "attribute_value", "value": { "selector": "#password", "attr": "required", "value": true }, "message": "Make the password field required" }, { "type": "attribute_value", "value": { "selector": "#password", "attr": "minlength", "value": "8" }, "message": "Add minlength=\"8\" to password" }, { "type": "attribute_value", "value": { "selector": "#terms", "attr": "required", "value": true }, "message": "Make the terms checkbox required" } ] } ] }