Formdown provides comprehensive client-side validation with visual feedback and programmatic access to validation results.
Overview
Both <formdown-ui>
and <formdown-editor>
components support form validation through the validate()
method. When validation errors occur, fields are automatically highlighted with visual feedback.
Validation Methods
validate()
Returns a validation result object with error details and applies visual feedback to invalid fields.
const form = document.querySelector('formdown-ui');
const result = form.validate();
if (result.isValid) {
console.log('Form is valid!');
// Proceed with form submission
} else {
console.log('Validation errors:', result.errors);
// Handle validation errors
}
Return Type:
interface ValidationResult {
isValid: boolean;
errors: FieldError[];
}
interface FieldError {
field: string; // Field name that failed validation
message: string; // Human-readable error message
}
Built-in Validation Rules
Required Fields
@name: [text required]
@email: [email required]
@terms: [checkbox required]
Input Type Validation
- Email: Validates email format
- URL: Validates URL format
- Tel: Validates phone number format
- Number: Validates numeric input
@email: [email required]
@website: [url]
@phone: [tel]
@age: [number min=18 max=120]
Length Validation
@username: [text required minlength=3 maxlength=20]
@bio: [textarea maxlength=500]
Pattern Validation
@username: [text pattern="[a-zA-Z0-9_]+" title="Only letters, numbers, and underscores"]
@zip: [text pattern="[0-9]{5}" title="5-digit ZIP code"]
Range Validation
@age: [number min=18 max=65]
@rating: [number min=1 max=5 step=0.5]
@birthdate: [date min="1900-01-01" max="2010-01-01"]
Visual Feedback
Error States
Fields that fail validation automatically receive:
- Red border color (
border-color: #dc2626
) - Error box shadow
- Error message below the field
Valid States
Fields that pass validation receive:
- Green border color (
border-color: #10b981
) - Success box shadow
CSS Classes
You can style validation states using these classes:
.field-error
: Applied to invalid fields.field-valid
: Applied to valid fields.validation-error-message
: Applied to error message elements
/* Custom error styling */
.field-error {
border-color: #ef4444 !important;
background-color: #fef2f2;
}
.validation-error-message {
color: #dc2626;
font-size: 0.75rem;
font-weight: 500;
}
JavaScript Examples
Basic Validation
<formdown-ui id="contact-form">
@name: [text required]
@email: [email required]
@phone: [tel]
@message: [textarea required minlength=10]
</formdown-ui>
<button onclick="handleSubmit()">Submit</button>
<script>
function handleSubmit() {
const form = document.getElementById('contact-form');
const validation = form.validate();
if (validation.isValid) {
const data = form.getFormData();
console.log('Submitting:', data);
// Submit to server
submitToServer(data);
} else {
console.error('Validation failed:', validation.errors);
// Show error summary
showErrorSummary(validation.errors);
}
}
function showErrorSummary(errors) {
const messages = errors.map(err => `${err.field}: ${err.message}`);
alert('Please fix the following errors:\n' + messages.join('\n'));
}
</script>
Real-time Validation
<formdown-ui id="signup-form">
@username: [text required minlength=3]
@password: [password required minlength=8]
@confirmPassword: [password required]
@email: [email required]
</formdown-ui>
<script>
const form = document.getElementById('signup-form');
// Validate on every change
form.addEventListener('formdown-change', () => {
const result = form.validate();
updateSubmitButton(result.isValid);
// Custom password confirmation check
const data = form.getFormData();
if (data.password && data.confirmPassword) {
validatePasswordMatch(data.password, data.confirmPassword);
}
});
function updateSubmitButton(isValid) {
const submitBtn = document.getElementById('submit-btn');
if (submitBtn) {
submitBtn.disabled = !isValid;
submitBtn.textContent = isValid ? 'Submit' : 'Please fix errors';
}
}
function validatePasswordMatch(password, confirmPassword) {
const confirmField = form.shadowRoot.querySelector('input[name="confirmPassword"]');
if (password !== confirmPassword) {
confirmField.classList.add('field-error');
// Add custom error message
addCustomError(confirmField, 'Passwords do not match');
} else {
confirmField.classList.remove('field-error');
removeCustomError(confirmField);
}
}
</script>
Editor Validation
<formdown-editor mode="split" id="form-editor">
@title: [text required maxlength=100]
@description: [textarea required minlength=20]
@category: [select required]
- Technology
- Design
- Business
@tags: [text pattern="[a-z,\s]+" title="Lowercase letters and commas only"]
</formdown-editor>
<div id="validation-status"></div>
<script>
const editor = document.getElementById('form-editor');
// Validate preview on content change
editor.addEventListener('contentChange', () => {
setTimeout(() => {
const result = editor.validate();
updateValidationStatus(result);
}, 100); // Small delay to allow UI update
});
function updateValidationStatus(result) {
const status = document.getElementById('validation-status');
if (result.isValid) {
status.innerHTML = '✅ Preview form is valid';
status.className = 'text-green-600';
} else {
const errorCount = result.errors.length;
status.innerHTML = `❌ Preview form has ${errorCount} error(s)`;
status.className = 'text-red-600';
}
}
</script>
Custom Validation
While Formdown provides comprehensive built-in validation, you can add custom validation logic:
function customValidation(formData) {
const errors = [];
// Custom business rules
if (formData.age && formData.category === 'senior' && formData.age < 65) {
errors.push({
field: 'age',
message: 'Senior category requires age 65 or older'
});
}
// Cross-field validation
if (formData.startDate && formData.endDate) {
const start = new Date(formData.startDate);
const end = new Date(formData.endDate);
if (start >= end) {
errors.push({
field: 'endDate',
message: 'End date must be after start date'
});
}
}
return errors;
}
// Use with built-in validation
function validateWithCustomRules() {
const form = document.querySelector('formdown-ui');
const builtInResult = form.validate();
const formData = form.getFormData();
const customErrors = customValidation(formData);
return {
isValid: builtInResult.isValid && customErrors.length === 0,
errors: [...builtInResult.errors, ...customErrors]
};
}
Error Handling
Graceful Degradation
function safeValidate(form) {
try {
return form.validate();
} catch (error) {
console.warn('Validation failed:', error);
return {
isValid: false,
errors: [{ field: 'general', message: 'Validation unavailable' }]
};
}
}
Accessibility
Validation errors are announced to screen readers through:
- ARIA labels on invalid fields
- Error messages linked to fields via
aria-describedby
- Visual focus indicators for keyboard navigation
Best Practices
- Validate early and often - Use real-time validation for better UX
- Clear error messages - Make validation errors specific and actionable
- Visual hierarchy - Use color, icons, and typography to guide attention
- Accessibility first - Ensure validation works with assistive technologies
- Custom validation - Supplement built-in rules with business logic
- Error recovery - Clear validation states when fields are corrected
- Submit protection - Disable submit buttons when validation fails
Validation Attributes Reference
Attribute | Types | Description | Example |
---|---|---|---|
required |
All | Field must have a value | [text required] |
minlength |
text, textarea | Minimum character length | [text minlength=3] |
maxlength |
text, textarea | Maximum character length | [text maxlength=50] |
min |
number, date | Minimum value/date | [number min=18] |
max |
number, date | Maximum value/date | [date max="2024-12-31"] |
step |
number | Numeric step value | [number step=0.5] |
pattern |
text, tel | Regular expression pattern | [text pattern="[0-9]+"] |
title |
All | Error message for pattern validation | [text pattern="[0-9]+" title="Numbers only"] |