A comprehensive class-based form validation library with 25+ built-in validators, async validation support, and advanced features for web applications
npm install nemo-validatorbash
npm install nemo-validator
`
Or using yarn:
`bash
yarn add nemo-validator
`
Basic Usage
$3
`html
Nemo Validator Example
`
$3
`javascript
import NemoValidator from 'nemo-validator';
document.addEventListener('DOMContentLoaded', function() {
// Initialize with default rules
const validator = new NemoValidator('nemo-validate-form');
// Store validator instance for features
window.nemoValidatorInstance = validator;
// Add a custom validation rule
validator.addRule('validate-password', {
pattern: /^(?=.[a-z])(?=.[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/,
message: 'Password must be at least 8 characters, include uppercase, lowercase and a number.',
filterPattern: /[^\w!@#$%^&*()]/g
});
// Validate all inputs when form is submitted
document.querySelector('.nemo-validate-form').addEventListener('submit', function(e) {
if (!validator.nemoValidateInputs()) {
e.preventDefault();
console.log('Form has validation errors');
}
});
});
`
Available Validation Rules
$3
| Rule Class | Validates | Description |
|------------|-----------|-------------|
| validate-name | Names | Letters, spaces, dots |
| validate-mobile | Mobile numbers | 10-digit format |
| validate-aadhar | Aadhar numbers | 12-digit format |
| validate-pan | PAN card numbers | Format: ABCDE1234F |
| validate-email | Email addresses | Standard email format |
| validate-address | Addresses | Letters, numbers, spaces, dots, forward slash |
| validate-pin | PIN codes | 6-digit format |
| validate-text | Text | Letters, spaces, dots, forward slash |
| validate-numeric | Numbers | Digits only |
| validate-business | Business names | Letters, numbers, spaces, dots, forward slash |
| validate-gst | GST numbers | Format: 22AAAAA0000A1Z5 |
| validate-uam | UAM numbers | Format: DL05A1234567 |
| validate-udyam | UDYAM numbers | Format: UDYAM-XX-00-0000000 |
| validate-amount | Amounts | Strictly blocks typing beyond 2 decimal places at the event level |
| validate-two-decimal | Amounts | Strictly blocks typing beyond 2 decimal places without using data attributes |
| validate-strong-password | Passwords | Minimum 8 characters with uppercase, lowercase, number and special character |
| validate-age | Age | Numbers between 18-100 with auto-constraints |
| validate-credit-card | Credit Cards | Auto-formats with spaces after every 4 digits |
$3
| Rule Class | Validates | Description |
|------------|-----------|-------------|
| validate-url | URLs | Web addresses with or without protocol |
| validate-phone-international | International Phone | Format: +1234567890 |
| validate-username | Usernames | 3-20 characters, letters, numbers, underscores |
| validate-postal-code | Postal Codes | 3-10 alphanumeric characters |
| validate-date-future | Future Dates | Dates that are in the future |
| validate-date-past | Past Dates | Dates that are in the past |
| validate-current-date | Current Date | Only today's date allowed |
| validate-time | Time | 24-hour format (HH:MM) |
| validate-color-hex | Hex Colors | Format: #FF0000 or #F00 |
| validate-percentage | Percentage | 0-100 with up to 2 decimals |
| validate-ip-address | IP Address | IPv4 format (192.168.1.1) |
| validate-mac-address | MAC Address | Format: 00:1B:44:11:3A:B7 |
| validate-slug | URL Slug | Lowercase letters, numbers, hyphens |
| validate-currency | Currency | Multi-currency support with auto-formatting (default: Rs.) |
| validate-social-security | SSN | Format: XXX-XX-XXXX |
| validate-license-plate | License Plate | 1-8 alphanumeric characters |
$3
The currency validation supports multiple international currencies with proper formatting and real-time validation. Each currency uses its native formatting conventions for thousand separators, decimal separators, and currency symbols.
#### How to Implement Currency Validation
Step 1: Add the CSS class to your input
`html
`
Step 2: Specify currency format using data-currency attribute
`html
`
Step 3: Initialize the validator
`javascript
const validator = new NemoValidator('your-form-class');
`
#### Supported Currency Formats
| Code | Currency | Symbol | Format Example | Decimal | Thousand | Grouping |
|------|----------|--------|----------------|---------|----------|----------|
| IN (default) | Indian Rupee | Rs. | Rs.12,34,567.89 | . | , | Indian |
| INR | Indian Rupee | ₹ | ₹12,34,567.89 | . | , | Indian |
| US | US Dollar | $ | $1,234,567.89 | . | , | Western |
| USD | US Dollar | $ | $1,234,567.89 | . | , | Western |
| EU | Euro | € | € 1.234.567,89 | , | . | Western |
| EUR | Euro | € | € 1.234.567,89 | , | . | Western |
| GB | British Pound | £ | £1,234,567.89 | . | , | Western |
| GBP | British Pound | £ | £1,234,567.89 | . | , | Western |
| JP | Japanese Yen | ¥ | ¥1,234,567.89 | . | , | Western |
| JPY | Japanese Yen | ¥ | ¥1,234,567.89 | . | , | Western |
| CN | Chinese Yuan | ¥ | ¥1,234,567.89 | . | , | Western |
| CNY | Chinese Yuan | ¥ | ¥1,234,567.89 | . | , | Western |
| RU | Russian Ruble | ₽ | ₽ 1 234 567,89 | , | space | Western |
| RUB | Russian Ruble | ₽ | ₽ 1 234 567,89 | , | space | Western |
| KR | Korean Won | ₩ | ₩1,234,567.89 | . | , | Western |
| KRW | Korean Won | ₩ | ₩1,234,567.89 | . | , | Western |
#### Complete Implementation Examples
Basic Form with Multiple Currencies:
`html
`
#### Currency Format Behavior
Indian Grouping (IN, INR):
- Pattern: 12,34,567.89 (first group of 3, then groups of 2)
- Example: User types "1234567" → Displays "Rs.12,34,567"
Western Grouping (US, GB, JP, etc.):
- Pattern: 1,234,567.89 (groups of 3 digits)
- Example: User types "1234567" → Displays "$1,234,567"
European Format (EU, EUR):
- Pattern: 1.234.567,89 (dots for thousands, comma for decimal)
- Example: User types "1234567.89" → Displays "€ 1.234.567,89"
Russian Format (RU, RUB):
- Pattern: 1 234 567,89 (spaces for thousands, comma for decimal)
- Example: User types "1234567.89" → Displays "₽ 1 234 567,89"
#### Key Features
- 🔄 Real-time formatting: Automatically formats as user types
- 💱 Multi-currency support: 8+ major currencies with native formatting
- ✅ Dynamic validation: Each currency validates according to its format rules
- 🎯 Auto-detection: Can detect currency format from existing values
- 📱 User-friendly: Prevents invalid input and provides immediate feedback
- 🌍 Localized: Respects regional formatting conventions
- ⚡ Performance optimized: Efficient real-time processing
#### Important Notes
1. Default Currency: If no data-currency attribute is specified, Indian Rupees (IN) format is used
2. Decimal Places: All currencies support up to 2 decimal places
3. Auto-formatting: The library automatically adds currency symbols and formatting
4. Validation: Each currency validates according to its specific format rules
5. Error Messages: Dynamic error messages show the correct format example for each currency
Key Validation Behavior
$3
Nemo Validator implements strict decimal place validation that:
- Blocks typing beyond the decimal limit at the keydown event level
- Prevents invalid input directly during the typing process
- Handles all validation events (keydown, paste, input) to ensure completeness
- Preserves cursor position after formatting
Example usage (as shown in the example files):
`html
`
API Reference
$3
`javascript
const validator = new NemoValidator(formClass, customRules);
`
- formClass: CSS class of the form(s) to validate
- customRules: (Optional) Object containing custom validation rules
$3
#### init()
Initializes the validator on the specified forms.
#### nemoValidateInputs()
Validates all inputs in the form and returns a boolean indicating if all inputs are valid.
Example:
`javascript
// Initialize the validator
const validator = new NemoValidator('nemo-validate-form');
// Validate on form submission
document.querySelector('.nemo-validate-form').addEventListener('submit', function(e) {
// Check if all inputs are valid
if (!validator.nemoValidateInputs()) {
// Prevent form submission if validation fails
e.preventDefault();
console.log('Form has validation errors');
} else {
console.log('All inputs are valid, proceeding with form submission');
// submit the form here
}
});
`
#### validateField(element)
Validates a single input field and shows/hides error messages.
- element: DOM element to validate
Example:
`javascript
// Get a reference to the input element
const amountInput = document.getElementById('amount');
amountInput.addEventListener('blur', function() {
// Call the validator to check the field
const isValid = validator.validateField(this);
if (isValid) {
console.log('Amount field is valid');
} else {
console.log('Amount field has validation errors');
}
});
`
#### addRule(name, rule)
Adds a custom validation rule.
- name: Name of the rule (prefix 'validate-' optional)
- rule: Object containing the rule details
- pattern: RegExp pattern to test against
- message: Error message to display
- filterPattern: RegExp pattern to filter input (optional)
- maxLength: Maximum input length (optional)
- setupEvents: Function to set up custom event handlers (optional)
- customValidation: Function for custom validation logic (optional)
Example:
`javascript
// Simplified custom rule that shows all available options
validator.addRule('my-decimal', {
// Basic validation pattern - allows exactly 2 decimal places
pattern: /^\d+\.\d{2}$/,
// Custom error message
message: 'Please enter a number with exactly 2 decimal places',
// Auto-filter out non-digits and extra dots
filterPattern: /[^\d.]/g,
// Maximum length constraint
maxLength: 10,
// Custom event handling
setupEvents: function(element) {
let lastValidValue = '';
const isValidInput = (value) => {
// Allow empty value or valid pattern
return !value || /^\d*\.?\d{0,2}$/.test(value);
};
element.addEventListener('keydown', function(e) {
// Allow navigation keys
if (e.key === 'Backspace' || e.key === 'Delete' ||
e.key === 'ArrowLeft' || e.key === 'ArrowRight' ||
e.key === 'Tab' || e.key === 'Home' || e.key === 'End' ||
e.ctrlKey || e.altKey || e.metaKey) {
return;
}
const newValue = this.value.substring(0, this.selectionStart) +
e.key +
this.value.substring(this.selectionEnd);
if (!isValidInput(newValue)) {
e.preventDefault();
}
});
element.addEventListener('input', function() {
if (isValidInput(this.value)) {
lastValidValue = this.value;
} else {
this.value = lastValidValue;
}
});
element.addEventListener('paste', function(e) {
const pastedText = (e.clipboardData || window.clipboardData).getData('text');
const newValue = this.value.substring(0, this.selectionStart) +
pastedText +
this.value.substring(this.selectionEnd);
if (!isValidInput(newValue)) {
e.preventDefault();
}
});
},
// Custom validation that runs during form validation
customValidation: function(value) {
if (!value) return false;
// Convert to number and check range
const num = parseFloat(value);
if (num < 0.01) {
this.message = 'Value must be at least 0.01';
return false;
}
if (num > 999.99) {
this.message = 'Value cannot exceed 999.99';
return false;
}
return true;
}
});
// Use this rule in HTML
//
`
#### removeRule(name)
Removes a validation rule.
- name: Name of the rule to remove
Example:
`javascript
// Remove the built-in PAN validation rule
validator.removeRule('validate-pan');
// Or remove a custom rule
validator.removeRule('validate-indian-mobile');
console.log('The rule has been removed and will no longer be applied');
`
#### getRules()
Gets all validation rules.
- Returns: Object containing all validation rules
Example:
`javascript
// Get all current validation rules
const allRules = validator.getRules();
// Log rules to console
console.log('Available validation rules:', allRules);
// check if a specific rule exists
if (allRules['validate-email']) {
console.log('Email validation rule exists with pattern:', allRules['validate-email'].pattern);
}
// iterate through all rules
Object.keys(allRules).forEach(ruleName => {
console.log(Rule: ${ruleName}, Message: ${allRules[ruleName].message});
});
`
#### getRule(name)
Gets a specific validation rule.
- name: Name of the rule to get (prefix 'validate-' optional)
- Returns: Rule object or null if not found
Example:
`javascript
// Get email validation rule
const emailRule = validator.getRule('email');
if (emailRule) {
console.log('Email pattern:', emailRule.pattern);
console.log('Email message:', emailRule.message);
}
// Check if rule exists
const customRule = validator.getRule('my-custom-rule');
if (!customRule) {
console.log('Custom rule not found');
}
`
#### hasRule(name)
Checks if a validation rule exists.
- name: Name of the rule to check (prefix 'validate-' optional)
- Returns: Boolean indicating if rule exists
Example:
`javascript
// Check if rules exist
if (validator.hasRule('email')) {
console.log('Email validation is available');
}
if (!validator.hasRule('custom-rule')) {
console.log('Need to add custom rule');
validator.addRule('custom-rule', {
pattern: /^custom$/,
message: 'Must be "custom"'
});
}
`
#### validateValue(ruleName, value)
Validates a value against a specific rule without DOM interaction.
- ruleName: Name of the rule to validate against
- value: Value to validate
- Returns: Object with isValid and message properties
Example:
`javascript
// Validate email without DOM
const emailResult = validator.validateValue('email', 'test@example.com');
if (emailResult.isValid) {
console.log('Email is valid');
} else {
console.log('Email error:', emailResult.message);
}
// Validate multiple values
const values = ['user@domain.com', 'invalid-email', ''];
values.forEach(email => {
const result = validator.validateValue('email', email);
console.log(${email}: ${result.isValid ? 'Valid' : result.message});
});
// Use in custom logic
function checkEmailAvailability(email) {
const validation = validator.validateValue('email', email);
if (!validation.isValid) {
return { available: false, error: validation.message };
}
// Proceed with availability check...
return { available: true };
}
`
#### getValidationErrors()
Gets validation errors for all fields in the form.
- Returns: Array of error objects with field, element, rule, message, and value properties
Example:
`javascript
// Get all validation errors
const errors = validator.getValidationErrors();
if (errors.length > 0) {
console.log('Form has errors:');
errors.forEach(error => {
console.log(Field: ${error.field}, Error: ${error.message});
});
// Focus on first error field
errors[0].element.focus();
} else {
console.log('Form is valid');
}
// Use in form submission
document.querySelector('form').addEventListener('submit', function(e) {
const errors = validator.getValidationErrors();
if (errors.length > 0) {
e.preventDefault();
// Show summary of errors
const errorSummary = errors.map(err => ${err.field}: ${err.message}).join('\n');
alert('Please fix the following errors:\n' + errorSummary);
}
});
`
#### clearValidationErrors()
Clears all validation errors and styling.
- Returns: Validator instance for method chaining
Example:
`javascript
// Clear all errors
validator.clearValidationErrors();
// Chain with other methods
validator
.clearValidationErrors()
.toggleFieldValidation(['email', 'phone'], false)
.setFieldError('username', 'Username is required');
// Use in form reset
document.querySelector('#resetBtn').addEventListener('click', function() {
document.querySelector('form').reset();
validator.clearValidationErrors();
});
`
#### toggleFieldValidation(fieldNames, enabled)
Enables or disables validation for specific fields.
- fieldNames: Field name(s) to enable/disable (string or array)
- enabled: Whether to enable (true) or disable (false) validation
- Returns: Validator instance for method chaining
Example:
`javascript
// Disable validation for specific fields
validator.toggleFieldValidation('email', false);
validator.toggleFieldValidation(['phone', 'address'], false);
// Re-enable validation
validator.toggleFieldValidation('email', true);
// Conditional validation based on user type
const userType = document.querySelector('#userType').value;
if (userType === 'guest') {
validator.toggleFieldValidation(['phone', 'address'], false);
} else {
validator.toggleFieldValidation(['phone', 'address'], true);
}
// Chain operations
validator
.clearValidationErrors()
.toggleFieldValidation('optionalField', false);
`
#### setFieldError(fieldName, message)
Sets a custom error message for a specific field.
- fieldName: Field name or ID
- message: Custom error message (empty string to clear)
- Returns: Validator instance for method chaining
Example:
`javascript
// Set custom error
validator.setFieldError('username', 'Username is already taken');
// Clear specific error
validator.setFieldError('username', '');
// Use with server-side validation
async function checkUsernameAvailability(username) {
try {
const response = await fetch('/check-username', {
method: 'POST',
body: JSON.stringify({ username }),
headers: { 'Content-Type': 'application/json' }
});
const result = await response.json();
if (!result.available) {
validator.setFieldError('username', 'Username is not available');
return false;
} else {
validator.setFieldError('username', ''); // Clear error
return true;
}
} catch (error) {
validator.setFieldError('username', 'Error checking username availability');
return false;
}
}
// Use in real-time checking
document.querySelector('#username').addEventListener('blur', async function() {
if (this.value) {
await checkUsernameAvailability(this.value);
}
});
`
#### getFormData()
Gets form data with validation status.
- Returns: Object containing formData, isValid, and errors properties
Example:
`javascript
// Get form data with validation
const result = validator.getFormData();
console.log('Form data:', result.formData);
console.log('Is valid:', result.isValid);
console.log('Errors:', result.errors);
// Use in form submission
document.querySelector('form').addEventListener('submit', function(e) {
e.preventDefault();
const result = validator.getFormData();
if (result.isValid) {
// Submit data
console.log('Submitting:', result.formData);
// Example: Send to server
fetch('/submit-form', {
method: 'POST',
body: JSON.stringify(result.formData),
headers: { 'Content-Type': 'application/json' }
});
} else {
console.log('Form has errors:', result.errors);
// Focus first error field
if (result.errors.length > 0) {
result.errors[0].element.focus();
}
}
});
// Use for auto-save functionality
setInterval(() => {
const result = validator.getFormData();
if (result.isValid && Object.keys(result.formData).length > 0) {
// Auto-save valid form data
localStorage.setItem('formDraft', JSON.stringify(result.formData));
}
}, 30000); // Auto-save every 30 seconds
`
Async Validation
Nemo Validator supports asynchronous validation for scenarios requiring API calls, database lookups, or other async operations.
$3
First, set up your HTML with the CSS class that matches your rule name:
`html
`
Then create the corresponding async validation rules in JavaScript:
`javascript
// Initialize validator
const validator = new NemoValidator('nemo-validate-form');
// Add async validation rule for username
// Rule name 'async-username' matches CSS class 'validate-async-username'
validator.addRule('async-username', {
message: 'Username is not available',
loadingMessage: 'Checking username availability...',
errorMessage: 'Unable to check username availability. Please try again.',
asyncValidation: async function(value) {
// Simulate API call
const response = await fetch(/api/check-username/${value});
const result = await response.json();
// Return boolean for simple validation
return result.available;
// Or return detailed result object
return {
isValid: result.available,
message: result.available ? 'Username is available!' : Username "${value}" is already taken
};
}
});
// Add async validation rule for email domain
// Rule name 'async-email' matches CSS class 'validate-async-email'
validator.addRule('async-email', {
message: 'Email domain is not accessible',
loadingMessage: 'Validating email domain...',
errorMessage: 'Unable to validate email domain. Please try again.',
asyncValidation: async function(value) {
// Basic email format check first
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailPattern.test(value)) {
return { isValid: false, message: 'Please enter a valid email format' };
}
// Simulate domain validation API call
const domain = value.split('@')[1];
const response = await fetch(/api/validate-domain/${domain});
const result = await response.json();
return {
isValid: result.isValid,
message: result.isValid ? 'Email domain is valid' : Domain "${domain}" is not accessible
};
}
});
`
How CSS Classes Connect to Rules:
- CSS class validate-async-username → Rule name async-username
- CSS class validate-async-email → Rule name async-email
- The library automatically adds the validate- prefix when looking for CSS classes
$3
#### validateValueAsync(ruleName, value)
Validates a value asynchronously against a specific rule.
`javascript
// Async validation
const result = await validator.validateValueAsync('async-username', 'john_doe');
console.log(result.isValid); // true/false
console.log(result.message); // Custom message
`
#### validateInputsAsync()
Validates all form inputs asynchronously.
`javascript
// Validate all inputs including async rules
const isValid = await validator.validateInputsAsync();
if (isValid) {
console.log('All validations passed!');
}
`
#### getValidationErrorsAsync()
Gets all validation errors including async validations.
`javascript
const errors = await validator.getValidationErrorsAsync();
errors.forEach(error => {
console.log(${error.field}: ${error.message});
});
`
#### getFormDataAsync()
Gets form data with async validation status.
`javascript
const result = await validator.getFormDataAsync();
console.log('Form Data:', result.formData);
console.log('Is Valid:', result.isValid);
console.log('Errors:', result.errors);
`
$3
- Loading States: Show custom loading messages during validation
- Error Handling: Graceful error handling with custom error messages
- Promise-based: Full Promise support for modern async/await patterns
- Mixed Validation: Seamlessly mix sync and async validations
- Custom Messages: Detailed validation results with custom success/error messages
$3
`javascript
document.querySelector('form').addEventListener('submit', async function(e) {
e.preventDefault();
try {
const result = await validator.getFormDataAsync();
if (result.isValid) {
// Submit form data
await submitForm(result.formData);
alert('Form submitted successfully!');
} else {
// Show validation errors
result.errors.forEach(error => {
console.log(${error.field}: ${error.message});
});
}
} catch (error) {
console.error('Validation failed:', error);
}
});
`
Creating Custom Rules with Event Validation
`javascript
// Custom rule with decimal validation
const myCustomRules = {
'validate-custom-decimal': {
pattern: /^[0-9]+(\.[0-9]{0,2})?$/,
message: 'Please enter a valid number with up to 2 decimal places',
filterPattern: /[^0-9.]/g,
setupEvents: function(element) {
// Setup custom event handlers
element.addEventListener('keydown', function(e) {
// Custom logic here
});
element.addEventListener('input', function() {
// Custom input handling
});
}
}
};
// Initialize with custom rules
const validator = new NemoValidator('my-form', myCustomRules);
``