
Product
Introducing Webhook Events for Alert Changes
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.
nemo-validator
Advanced tools
A comprehensive class-based form validation library with 25+ built-in validators, async validation support, and advanced features for web applications
A lightweight JavaScript class-based form validation library that helps validate different types of inputs in web forms at the event level.
Install the package using npm:
npm install nemo-validator
Or using yarn:
yarn add nemo-validator
<!DOCTYPE html>
<html>
<head>
<title>Nemo Validator Example</title>
<style>
.text-danger {
color: red;
font-size: 0.8rem;
margin-top: 5px;
display: block;
}
</style>
</head>
<body>
<form class="nemo-validate-form">
<div>
<label for="name">Name:</label>
<input type="text" id="name" name="name" class="validate-name">
</div>
<div>
<label for="email">Email:</label>
<input type="email" id="email" name="email" class="validate-email">
</div>
<div>
<label for="mobile">Mobile:</label>
<input type="text" id="mobile" name="mobile" class="validate-mobile">
</div>
<div>
<label for="amount">Amount:</label>
<input type="text" id="amount" name="amount" class="validate-two-decimal" placeholder="Enter amount (e.g., 123.45)">
<!-- Strictly blocks input after 2 decimal places -->
</div>
<button type="submit">Submit Form</button>
</form>
<script src="node_modules/nemo-validator/dist/index.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize the validator
const validator = new NemoValidator('nemo-validate-form');
// Store validator instance for features
window.nemoValidatorInstance = validator;
// Validate form on submit
document.querySelector('.nemo-validate-form').addEventListener('submit', function(e) {
if (!validator.nemoValidateInputs()) {
e.preventDefault();
alert('Please fix the errors in the form.');
}
});
});
</script>
</body>
</html>
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');
}
});
});
| 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 |
| 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 |
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.
Step 1: Add the CSS class to your input
<input type="text" class="validate-currency" name="amount" id="amount">
Step 2: Specify currency format using data-currency attribute
<!-- For Euro -->
<input type="text" class="validate-currency" data-currency="EU" name="price" id="price">
<!-- For US Dollar -->
<input type="text" class="validate-currency" data-currency="US" name="salary" id="salary">
Step 3: Initialize the validator
const validator = new NemoValidator('your-form-class');
| 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 |
Basic Form with Multiple Currencies:
<form class="nemo-validate-form">
<!-- Default Indian Rupees (no data-currency needed) -->
<div>
<label for="price-inr">Price (Indian Rupees):</label>
<input type="text" id="price-inr" name="price-inr" class="validate-currency"
placeholder="Rs.12,34,567.89">
</div>
<!-- US Dollar -->
<div>
<label for="price-usd">Price (US Dollar):</label>
<input type="text" id="price-usd" name="price-usd" class="validate-currency"
data-currency="US" placeholder="$1,234,567.89">
</div>
<!-- Euro (uses comma as decimal separator) -->
<div>
<label for="price-eur">Price (Euro):</label>
<input type="text" id="price-eur" name="price-eur" class="validate-currency"
data-currency="EU" placeholder="€ 1.234.567,89">
</div>
<!-- British Pound -->
<div>
<label for="price-gbp">Price (British Pound):</label>
<input type="text" id="price-gbp" name="price-gbp" class="validate-currency"
data-currency="GB" placeholder="£1,234,567.89">
</div>
<button type="submit">Submit</button>
</form>
<script>
// Initialize validator
const validator = new NemoValidator('nemo-validate-form');
// Form submission with validation
document.querySelector('.nemo-validate-form').addEventListener('submit', function(e) {
e.preventDefault();
if (validator.nemoValidateInputs()) {
const formData = validator.getFormData();
console.log('Valid form data:', formData.formData);
// Process form submission
} else {
alert('Please fix the currency format errors.');
}
});
</script>
Indian Grouping (IN, INR):
Western Grouping (US, GB, JP, etc.):
European Format (EU, EUR):
Russian Format (RU, RUB):
data-currency attribute is specified, Indian Rupees (IN) format is usedNemo Validator implements strict decimal place validation that:
Example usage (as shown in the example files):
<!-- For amounts with up to 2 decimal places -->
<input type="text" id="amount" name="amount" class="validate-two-decimal" placeholder="Enter amount (e.g., 123.45)">
const validator = new NemoValidator(formClass, customRules);
formClass: CSS class of the form(s) to validatecustomRules: (Optional) Object containing custom validation rulesinit()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:
// 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 validateExample:
// 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 againstmessage: Error message to displayfilterPattern: 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:
// 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
// <input type="text" class="validate-my-decimal" placeholder="123.45">
removeRule(name)Removes a validation rule.
name: Name of the rule to removeExample:
// 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.
Example:
// 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)Example:
// 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)Example:
// 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 againstvalue: Value to validateisValid and message propertiesExample:
// 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.
Example:
// 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.
Example:
// 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) validationExample:
// 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 IDmessage: Custom error message (empty string to clear)Example:
// 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.
formData, isValid, and errors propertiesExample:
// 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
Nemo Validator supports asynchronous validation for scenarios requiring API calls, database lookups, or other async operations.
First, set up your HTML with the CSS class that matches your rule name:
<form class="nemo-validate-form">
<div>
<label for="username">Username:</label>
<!-- The class 'validate-async-username' connects to the rule 'async-username' -->
<input type="text" id="username" name="username" class="validate-async-username"
placeholder="Enter username to check availability">
</div>
<div>
<label for="email">Email:</label>
<!-- The class 'validate-async-email' connects to the rule 'async-email' -->
<input type="email" id="email" name="email" class="validate-async-email"
placeholder="Enter email for domain validation">
</div>
<button type="submit">Submit Form</button>
</form>
Then create the corresponding async validation rules in 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:
validate-async-username → Rule name async-usernamevalidate-async-email → Rule name async-emailvalidate- prefix when looking for CSS classesvalidateValueAsync(ruleName, value)Validates a value asynchronously against a specific rule.
// 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.
// 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.
const errors = await validator.getValidationErrorsAsync();
errors.forEach(error => {
console.log(`${error.field}: ${error.message}`);
});
getFormDataAsync()Gets form data with async validation status.
const result = await validator.getFormDataAsync();
console.log('Form Data:', result.formData);
console.log('Is Valid:', result.isValid);
console.log('Errors:', result.errors);
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);
}
});
// 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);
Nemo Validator works in all modern browsers:
MIT
FAQs
A comprehensive class-based form validation library with 25+ built-in validators, async validation support, and advanced features for web applications
The npm package nemo-validator receives a total of 16 weekly downloads. As such, nemo-validator popularity was classified as not popular.
We found that nemo-validator demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.

Security News
ENISA has become a CVE Program Root, giving the EU a central authority for coordinating vulnerability reporting, disclosure, and cross-border response.

Product
Socket now scans OpenVSX extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.