form.isValid
Quick Start (30 seconds)
const { v } = Forms;
const form = Forms.create(
{ email: '', password: '' },
{
validators: {
email: v.email('Invalid email'),
password: v.minLength(8, 'Min 8 chars')
}
}
);
console.log(form.isValid); // true (initially, fields empty = optional)
form.setValue('email', 'invalid');
console.log(form.isValid); // false (email has error)
form.setValue('email', 'user@example.com');
console.log(form.isValid); // true (no errors)
form.setValue('password', 'short');
console.log(form.isValid); // false (password too short)
form.setValue('password', 'secret123');
console.log(form.isValid); // true ✅ (all valid!)What just happened? form.isValid automatically tells you if the entire form is valid. It's a computed property that checks if there are any errors!
What is form.isValid?
form.isValid is a computed boolean property that indicates whether the entire form is valid (has no validation errors).
Simply put, it's true when no fields have errors, and false when at least one field has an error.
Think of form.isValid as a green light - it tells you whether it's safe to proceed with submission.
Syntax
// Read the validity state
if (form.isValid) {
console.log('Form is valid!');
}
// Enable/disable submit button
submitButton.disabled = !form.isValid;
// Show status
statusText.textContent = form.isValid ? 'Ready to submit' : 'Please fix errors';Type: Boolean (read-only, computed)
Values:
true- No validation errors existfalse- One or more validation errors exist
Why Does This Exist?
The Problem: Manual Validity Checking
Without a computed property, you'd check validity manually:
// Manual validity checking (tedious!)
function isFormValid() {
// Check each field manually
if (form.errors.email) return false;
if (form.errors.password) return false;
if (form.errors.username) return false;
if (form.errors.age) return false;
// ... check every field
return true;
}
// Or check if errors object is empty
function isFormValid() {
return Object.keys(form.errors).length === 0;
}
// Have to call this function everywhere
if (isFormValid()) {
enableSubmitButton();
}Problems: ❌ Repetitive validity checks ❌ Easy to forget to check new fields ❌ Not reactive - have to call manually ❌ Verbose code everywhere
The Solution with form.isValid
const { v } = Forms;
const form = Forms.create(
{ email: '', password: '', username: '' },
{
validators: {
email: v.email('Invalid'),
password: v.minLength(8, 'Too short'),
username: v.minLength(3, 'Too short')
}
}
);
// Just check the computed property!
if (form.isValid) {
console.log('All valid!');
}
// Reactive - updates automatically
effect(() => {
const button = document.getElementById('submit');
button.disabled = !form.isValid;
// Updates whenever any validation changes ✅
});Benefits: ✅ Single source of truth for validity ✅ Automatically updates when errors change ✅ No manual validity checks needed ✅ Reactive - triggers effects automatically ✅ Concise and readable code
Mental Model
Think of form.isValid like a quality control inspector:
Manual Checking (Inspector Checks Every Item)
Inspector: "Let me check each item..."
*Checks email* "OK"
*Checks password* "OK"
*Checks username* "OK"
"All items passed!"
New item added:
Inspector: "Let me check EVERYTHING again..."
*Repeats entire process*form.isValid (Automated Quality System)
Quality System:
┌────────────────────────┐
│ Items to Check: │
│ ✓ Email: Valid │
│ ✓ Password: Valid │
│ ✓ Username: Valid │
├────────────────────────┤
│ Status: ✅ ALL VALID │
└────────────────────────┘
New item added:
Quality System: *Automatically recalculates*
Status: ❌ HAS ERRORS
(Instant, automatic!)Key Insight: form.isValid is computed automatically - it always reflects the current validity state without manual checking.
How Does It Work?
Computation Logic
// Internal computation (simplified):
get isValid() {
const errorKeys = Object.keys(this.errors);
// No error keys? Valid!
if (errorKeys.length === 0) return true;
// Has error keys? Check if any have actual errors
return errorKeys.every(key => !this.errors[key]);
}Automatic Updates
User calls form.setValue('email', 'invalid')
↓
Validator runs
↓
form.errors.email = 'Invalid email'
↓
form.isValid recomputes (automatically!)
↓
form.isValid = false
↓
Effects that depend on isValid runBasic Usage
Example 1: Enable/Disable Submit Button
const { v } = Forms;
const form = Forms.create(
{ email: '', password: '' },
{
validators: {
email: v.combine(v.required('Required'), v.email('Invalid')),
password: v.combine(v.required('Required'), v.minLength(8, 'Too short'))
}
}
);
const submitButton = document.getElementById('submit');
// Disable button if form is invalid
effect(() => {
submitButton.disabled = !form.isValid;
});
// Try it
form.setValue('email', 'invalid');
// submitButton.disabled = true (form invalid)
form.setValue('email', 'user@example.com');
form.setValue('password', 'secret123');
// submitButton.disabled = false (form valid) ✅Example 2: Show Validation Status
const { v } = Forms;
const form = Forms.create(
{ username: '', email: '' },
{
validators: {
username: v.required('Required'),
email: v.email('Invalid')
}
}
);
effect(() => {
const statusEl = document.getElementById('status');
if (form.isValid) {
statusEl.textContent = '✅ Form is ready to submit';
statusEl.className = 'status-success';
} else {
statusEl.textContent = '❌ Please fix errors';
statusEl.className = 'status-error';
}
});Example 3: Conditional Submit
const form = Forms.create(
{ data: '' },
{ /* validators */ }
);
async function handleSubmit() {
// Only submit if valid
if (!form.isValid) {
alert('Please fix all errors before submitting');
return;
}
await form.submit();
}Example 4: Progress Indicator
const { v } = Forms;
const form = Forms.create(
{ step1: '', step2: '', step3: '' },
{
validators: {
step1: v.required('Required'),
step2: v.required('Required'),
step3: v.required('Required')
}
}
);
effect(() => {
const progressBar = document.getElementById('progress');
// Calculate valid fields
const totalFields = Object.keys(form.values).length;
const validFields = totalFields - Object.keys(form.errors).length;
const percentage = (validFields / totalFields) * 100;
progressBar.style.width = `${percentage}%`;
progressBar.textContent = form.isValid ? 'Complete!' : `${Math.round(percentage)}%`;
});Advanced Patterns
Pattern 1: Multi-Step Form Validation
const { v } = Forms;
// Step 1 form
const step1 = Forms.create(
{ name: '', email: '' },
{
validators: {
name: v.required('Required'),
email: v.email('Invalid')
}
}
);
// Step 2 form
const step2 = Forms.create(
{ address: '', phone: '' },
{
validators: {
address: v.required('Required'),
phone: v.pattern(/^\d{10}$/, 'Invalid phone')
}
}
);
function canProceedToNextStep() {
return step1.isValid;
}
function canSubmitFinalForm() {
return step1.isValid && step2.isValid;
}
// Next button
effect(() => {
document.getElementById('next').disabled = !canProceedToNextStep();
});
// Submit button
effect(() => {
document.getElementById('submit').disabled = !canSubmitFinalForm();
});Pattern 2: Conditional Field Requirements
const { v } = Forms;
const form = Forms.create(
{
accountType: 'personal',
companyName: '',
taxId: ''
},
{
validators: {
companyName: (value, allValues) => {
if (allValues.accountType === 'business' && !value) {
return 'Required for business accounts';
}
return null;
},
taxId: (value, allValues) => {
if (allValues.accountType === 'business' && !value) {
return 'Required for business accounts';
}
return null;
}
}
}
);
// form.isValid adapts to account type
effect(() => {
console.log('Form valid?', form.isValid);
// true for personal (no company fields required)
// false for business (company fields required but empty)
});Pattern 3: Partial Validation
const form = Forms.create(
{ email: '', password: '', newsletter: false },
{ /* validators for email and password */ }
);
// Check if critical fields are valid
function areCriticalFieldsValid() {
const criticalFields = ['email', 'password'];
return criticalFields.every(field => !form.errors[field]);
}
// Allow save draft even if not fully valid
function canSaveDraft() {
return areCriticalFieldsValid();
}
// Require full validity for submit
function canSubmit() {
return form.isValid;
}Pattern 4: Validation Warning System
const { v } = Forms;
const form = Forms.create(
{ email: '', password: '' },
{
validators: {
email: v.email('Invalid'),
password: v.minLength(8, 'Too short')
}
}
);
effect(() => {
const warningEl = document.getElementById('warning');
if (!form.isValid && form.isDirty) {
const errorCount = Object.keys(form.errors).length;
warningEl.textContent = `⚠️ ${errorCount} error(s) found`;
warningEl.style.display = 'block';
} else {
warningEl.style.display = 'none';
}
});Common Pitfalls
Pitfall 1: Checking isValid Before Validation
❌ Wrong:
const { v } = Forms;
const form = Forms.create(
{ email: '' },
{ validators: { email: v.required('Required') } }
);
// Check immediately - validators haven't run yet!
if (form.isValid) {
console.log('Valid!'); // true, but misleading!
}✅ Correct:
const { v } = Forms;
const form = Forms.create(
{ email: '' },
{ validators: { email: v.required('Required') } }
);
// Trigger validation first
form.validate();
// Or set a value (triggers validation)
form.setValue('email', '');
// Now check
if (form.isValid) {
console.log('Valid!');
}Pitfall 2: Assuming Empty Form is Invalid
❌ Wrong:
const form = Forms.create(
{ email: '' },
{ validators: { email: v.email('Invalid') } }
);
console.log(form.isValid);
// true! (email validator allows empty by default)✅ Correct:
const form = Forms.create(
{ email: '' },
{
validators: {
email: v.combine(
v.required('Required'), // Add required!
v.email('Invalid')
)
}
}
);
console.log(form.isValid); // false (required field empty)Pitfall 3: Not Validating Before Checking isValid
❌ Wrong:
const form = Forms.create(
{ data: '' },
{ /* validators */ }
);
// Just checking, without triggering validation
if (form.isValid) {
await form.submit();
}✅ Correct:
const form = Forms.create(
{ data: '' },
{ /* validators */ }
);
// Validate first
const isValid = form.validate();
if (isValid) {
await form.submit();
}
// Or use submit() which validates automatically
const result = await form.submit();Summary
Key Takeaways
form.isValidis a computed property that checks if the form has no errors.It's read-only - you can't set it directly; it updates automatically.
Updates automatically when errors change (after validation).
Perfect for submit button state -
button.disabled = !form.isValid.Reactive - triggers effects when validity changes.
Checks all fields -
trueonly if no field has errors.Returns
truefor empty optional fields - combine validators withrequired()for mandatory fields.Use
validate()first if you need to check validity before user interaction.
One-Line Rule
form.isValidautomatically tells you if the form is error-free - use it to enable/disable submit buttons and show validation status.
What's Next?
- Learn about
form.isDirtyto detect form changes - Explore
form.hasErrorsto check error existence - Master
form.errorFieldsto get fields with errors - Discover advanced validation patterns