- Remove presentational classes (.form-group, .required, .hint, .checkbox-group) - Replace <span class="required">*</span> with plain * in label text - Replace <div class="hint"> with semantic <small> element - Simplify checkbox markup to use native label wrapping pattern - Update previewBaseCSS to style semantic elements directly - Add code quality standards to CLAUDE.md emphasizing WCAG compliance and native HTML
113 lines
8.2 KiB
JSON
113 lines
8.2 KiB
JSON
{
|
|
"$schema": "../schemas/code-crispies-module-schema.json",
|
|
"id": "html-forms-validation",
|
|
"title": "HTML Forms: Validation",
|
|
"description": "Learn HTML5 built-in form validation attributes",
|
|
"mode": "html",
|
|
"difficulty": "intermediate",
|
|
"lessons": [
|
|
{
|
|
"id": "required-fields",
|
|
"title": "Required Fields",
|
|
"description": "The <kbd>required</kbd> attribute prevents form submission if the field is empty.<br><br>Add it to any input that must be filled:<br><kbd><input type=\"text\" required></kbd><br><br>The browser shows a validation message automatically.",
|
|
"task": "Make both the name and email fields required by adding the <kbd>required</kbd> 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": "<form>\n <label for=\"name\">Name: *</label>\n <input type=\"text\" id=\"name\" name=\"name\">\n \n <label for=\"email\">Email: *</label>\n <input type=\"email\" id=\"email\" name=\"email\">\n \n <button type=\"submit\">Submit</button>\n</form>",
|
|
"solution": "<form>\n <label for=\"name\">Name: *</label>\n <input type=\"text\" id=\"name\" name=\"name\" required>\n \n <label for=\"email\">Email: *</label>\n <input type=\"email\" id=\"email\" name=\"email\" required>\n \n <button type=\"submit\">Submit</button>\n</form>",
|
|
"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": "Input Constraints",
|
|
"description": "Control what users can enter:<br><br><kbd>minlength</kbd> / <kbd>maxlength</kbd> - Text length limits<br><kbd>min</kbd> / <kbd>max</kbd> - Number range<br><kbd>pattern</kbd> - Regex pattern matching<br><kbd>placeholder</kbd> - Hint text (not a label!)",
|
|
"task": "Add validation to the password input:<br>1. Add <kbd>minlength=\"8\"</kbd> for minimum length<br>2. Add <kbd>maxlength=\"20\"</kbd> for maximum length<br>3. Add <kbd>placeholder=\"Enter password\"</kbd> 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": "<form>\n <label for=\"password\">Password:</label>\n <input type=\"password\" id=\"password\" name=\"password\" required>\n <small>Must be 8-20 characters</small>\n \n <button type=\"submit\">Create Account</button>\n</form>",
|
|
"solution": "<form>\n <label for=\"password\">Password:</label>\n <input type=\"password\" id=\"password\" name=\"password\" required minlength=\"8\" maxlength=\"20\" placeholder=\"Enter password\">\n <small>Must be 8-20 characters</small>\n \n <button type=\"submit\">Create Account</button>\n</form>",
|
|
"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": "Complete Registration Form",
|
|
"description": "Build a complete registration form with all validation concepts:<br><br>- Required fields marked with *<br>- Email validation (use type=\"email\")<br>- Password with length constraints<br>- Terms checkbox (required)<br>- 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": "<form>\n <h2>Create Account</h2>\n \n <label for=\"fullname\">Full Name *</label>\n <input type=\"text\" id=\"fullname\" name=\"fullname\">\n \n <label for=\"email\">Email *</label>\n <input id=\"email\" name=\"email\">\n \n <label for=\"password\">Password *</label>\n <input id=\"password\" name=\"password\">\n \n <label>\n <input type=\"checkbox\" id=\"terms\" name=\"terms\">\n I agree to the Terms of Service *\n </label>\n \n <button type=\"submit\">Register</button>\n</form>",
|
|
"solution": "<form>\n <h2>Create Account</h2>\n \n <label for=\"fullname\">Full Name *</label>\n <input type=\"text\" id=\"fullname\" name=\"fullname\" required>\n \n <label for=\"email\">Email *</label>\n <input type=\"email\" id=\"email\" name=\"email\" required>\n \n <label for=\"password\">Password *</label>\n <input type=\"password\" id=\"password\" name=\"password\" required minlength=\"8\">\n \n <label>\n <input type=\"checkbox\" id=\"terms\" name=\"terms\" required>\n I agree to the Terms of Service *\n </label>\n \n <button type=\"submit\">Register</button>\n</form>",
|
|
"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 to '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 to '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"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|