Using Lodash conformsTo for Form Validation
This article provides an overview of how the Lodash
_.conformsTo method can be applied to web form validation.
By mapping form field values to specific validator functions, developers
can perform declarative, schema-like checks across an entire form
payload. Below, we explore practical use cases, code examples, and the
operational benefits of using this method to handle client-side form
logic.
Understanding
_.conformsTo
The _.conformsTo method checks if an object
conforms to a source object of predicate functions. It
returns true if all predicate functions return truthy
values for corresponding properties in the target object, and
false otherwise:
_.conformsTo(object, source);In form validation, the object represents the user's
input data, while the source acts as a validation schema
where keys match input names and values are validation rules.
1. Single-Step Registration and Signup Forms
The most common use case is validating standard user registration fields—such as usernames, email addresses, and passwords—before submitting the payload.
import _ from 'lodash';
const formData = {
username: 'dev_user',
email: 'user@example.com',
age: 22,
termsAccepted: true
};
const registrationSchema = {
username: (val) => typeof val === 'string' && val.trim().length >= 3,
email: (val) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val),
age: (val) => Number.isInteger(val) && val >= 18,
termsAccepted: (val) => val === true
};
const isFormValid = _.conformsTo(formData, registrationSchema);Using _.conformsTo ensures that every field meets its
criteria in a single declarative call, avoiding long chains of
if-else or nested boolean operators.
2. Multi-Step (Wizard) Forms
In multi-step checkout or onboarding flows, validating the current step before allowing the user to proceed is critical. You can define separate schema objects for each step and evaluate them dynamically.
const wizardData = {
step1: { fullName: 'Jane Doe', phone: '1234567890' },
step2: { shippingAddress: '123 Main St', postalCode: '90210' }
};
const stepValidators = {
1: {
fullName: (val) => Boolean(val && val.length > 0),
phone: (val) => /^\d{10}$/.test(val)
},
2: {
shippingAddress: (val) => Boolean(val && val.length > 5),
postalCode: (val) => /^\d{5}$/.test(val)
}
};
function canProceedToNextStep(currentStepNumber, data) {
const currentValidator = stepValidators[currentStepNumber];
return _.conformsTo(data, currentValidator);
}This approach encapsulates step-specific rules and makes adding, removing, or reordering steps straightforward.
3. Real-Time Submit Button State Management
Disabling a submit button until all required inputs are valid is a
common UI pattern. Because _.conformsTo returns a boolean
immediately, it can run efficiently inside reactive frameworks on every
input change.
function onInputChange(updatedFormData) {
const submitButton = document.querySelector('#submit-btn');
const rules = {
cardNumber: (val) => /^\d{16}$/.test(val),
cvv: (val) => /^\d{3,4}$/.test(val),
expiryMonth: (val) => val >= 1 && val <= 12
};
submitButton.disabled = !_.conformsTo(updatedFormData, rules);
}This ensures fast evaluations without the overhead of instantiating heavy validation libraries on simple forms.
4. Conditional and Role-Based Validation
Enterprise applications often adjust required fields based on the user's role or selected choices (e.g., business accounts vs. individual accounts). Validation schemas can be composed modularly.
const baseAccountRules = {
email: (val) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val),
password: (val) => typeof val === 'string' && val.length >= 8
};
const corporateAccountRules = {
...baseAccountRules,
taxId: (val) => /^[0-9]{9}$/.test(val),
companyName: (val) => typeof val === 'string' && val.length > 2
};
function validateAccountCreation(formData, isCorporate) {
const rules = isCorporate ? corporateAccountRules : baseAccountRules;
return _.conformsTo(formData, rules);
}By leveraging object spread syntax, rules can be inherited and combined cleanly depending on runtime conditions.
Limitations to Consider
While _.conformsTo is lightweight and clear, it has
specific constraints in form validation:
- Boolean Return Only: It returns
trueorfalse. It does not return custom error messages or tell you which specific field failed. - Synchronous Execution: Predicate functions must be synchronous; it cannot handle asynchronous checks such as verifying username availability via an API.
For complex forms needing detailed per-field error messages, consider
combining _.conformsTo with custom field error trackers, or
reserving it for high-level submission guards.