Validating form input to only allow numeric values is a critical task in web development. User-provided data often needs to be restricted to numbers for later processing by applications. However, invalid formats could break functionality. This guide will provide an in-depth examination of the best practices for ensuring numbers-only validation in JavaScript.
Why Numeric Validation Matters
Rejecting non-numeric input protects apps from data inconsistencies and errors commonly caused by incorrect formatting or data types:
- Inserting letters/symbols into a database number column can crash apps
- Math operations like
toFixed()fail on non-numbers causing NaN errors - Dates expected numbers for operations break with strings input
According to web industry surveys, around 25-30% of web form submissions contain invalid or improper data. Catching this early with JavaScript validation improves the experience and data integrity.
Overview of JavaScript Validation Methods
JavaScript offers various handy methods for validating numbers:
- Regular expressions – Powerful pattern matching
- isNaN() – Check if not a number
- Number constructor – Convert and check return
- Custom functions – Flexible logic checks
- Validation libraries – Robust pre-built tools
Additionally, unobtrusive methods like progressive enhancement focus on stability while enhancing sites with JavaScript.
Let‘s explore the best practices for each approach…
Regular Expressions
Regex formulas define strict matching patterns. For numbers, a basic regex checks if input only contains digits 0-9:
const numericRegex = /^[0-9]+$/;
The anchors ^ and $ force full string match against one or more (+) digits \d.
This validation check passes for numbers while rejecting strings:
numericRegex.test(‘555‘); // true
numericRegex.test(‘123abc‘); // false
Regex provides fast, powerful number checking that is highly customizable. Variants can match decimal points, thousand separators, currency symbols and more.
isNaN() for Numerics
The isNaN() function checks if the provided value "is Not a Number". This handles conversion internally:
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
Here we add the isFinite() check to also catch Infinity which slips through isNaN().
The benefit of isNaN() is simplicity – no need to manage conversion and it works across browsers. However, it depends on implicit coercion which could produce false positives.
Number Constructor
The Number constructor offers a stricter approach:
function isNumber(n) {
return n === Number(n);
}
Here we check equivalence of the raw value against the constructed number. If no valid conversion could be made, Number() returns NaN failing equality.
This avoids issues with more permissive coercion by explicitly handling conversion then testing the result. However, complex values like hex numbers with prefixes may be rejected incorrectly.
Custom Function Logic
For ultimate flexibility, completely custom validators allow tailored logic. For example, this uses type checking:
function isNumeric(n) {
return (typeof n === ‘number‘ ||
(typeof n === ‘string‘ &&
!isNaN(Number(n))));
}
The function first checks if value is already a true number. If not, strings are converted to test if valid numbers.
Custom functions work great for business rules going beyond basic numerics. But require more up front effort compared to built-ins.
Validation Libraries
For comprehensive solutions across many validation needs, leveraging a dedicated library like Validate.js can help:
import validate from ‘validate.js‘;
const valid = validate.single(
value,
{
presence: true,
numericality: {
onlyInteger: true,
strict: true
}
}
);
The library checks presence requiring the value, then runs a robust set of number checks including integers only and strict parsing.
Large projects with many forms can benefit from extensive pre-built features in validation libraries. However, smaller apps may not require this overhead.
Unobtrusive Progressive Enhancement
Validation should focus on enhancing existing behavior rather than dictating functionality. This progressive enhancement approach avoids issues when JavaScript fails or is disabled:
<form>
<input type="number" min="0" max="10">
</form>
The native HTML input validation handles core behavior. Non-JS environments retain basic functioning. We then layer JS on top without breaking base form usage:
function validate(input) {
const num = parseInt(input.value);
if (isNaN(num)) {
// Improves validation feedback
}
}
This future-proofs against potential JS failures and provides stability with basal validation in place.
Putting into Practice
With a solid grasp of the techniques available, let‘s walk through implementing numbers-only validation for a real-world example using HTML and JavaScript…
Our Form
We need to build an order form that collects numeric details including quantities and cost values. Invalid data could cause major business issues.
We‘ll create inputs for:
- Units quantity
- Unit cost
- Total order cost
The total cost will automatically tally units and cost.
The JavaScript
First we need JavaScript to hook into the form and inputs:
const orderForm = document.getElementById(‘orderForm‘);
const unitsInput = document.getElementById(‘units‘);
const unitCost = document. getElementById(‘unitCost‘);
orderForm.addEventListener(‘input‘, validate);
function validate() {
// Gets called on any input change
}
This watches for changes to begin validation.
Next we define the checks:
function validate() {
const u = parseInt(unitsInput.value);
const c = parseFloat(unitCost.value);
if (isNaN(u) || !isFinite(u)) {
// Units validation fail
}
if (isNaN(c) || !isFinite(c)) {
// Cost validation fail
}
}
Using parseInt and parseFloat allows a lenient conversion while still testing the result. This handles valid special values like empty string.
For failure messaging, we modify the DOM:
function validate() {
if (isNaN(u)) {
unitsInput.setCustomValidity(‘Must enter numbers‘);
} else {
unitsInput.setCustomValidity(‘‘); // Clear message
}
// Set validity on cost input too
}
The setCustomValidity() method displays a built-in browser error.
To finish validation, we recalculate and check order total:
function validate() {
// Units & cost validation
if (!isNaN(u) && !isNaN(c)) {
const total = u * c;
if (isNaN(total)) {
// Still a validation issue
displayError(‘Check inputs‘);
}
}
}
If units and cost pass but total is NaN, we display a generic error alerting the user something needs fixed.
This provides robust validation coverage across the important business values.
Progressive Enhancement
To progressively enhance, we add min, max, and step attributes:
<input id="units" type="number" min="0" max="1000">
<input id="unitCost" type="number" min="0" step="0.01">
Now if JavaScript breaks, the form retains basic numeric validation ability through HTML alone.
We don‘t alter this functionality – only improve it. This fails gracefully enhancing site stability.
Additional Considerations
Further techniques can improve numeric validation fidelity in complex situations:
- Trim input to remove spaces impacting conversion
- Checkempties explicitly with strict equality
- Support international number formats
- Compare pre- and post-conversion values
- Restrict scientific notation that passes checks
- Use fallback checks like regex if ops fail
Latency can also be optimized. Move repetitive operations outside main logic and cache selector objects.
Conclusion
JavaScript validation plays an important role in restricting web form fields to numbers-only input. Key options to implement this include regular expressions, conversion checks like parseInt() combined with isNaN(), leveraging validation libraries, or custom logic handling.
Following progressive enhancement principles ensures baseline functionality without JavaScript, while layering enhanced validation on top.
Approaching implementation with sound practices, and attention to detail around edge cases, results in solid number validation helping catch bogus data before it reaches applications. Treat validation as an ongoing incremental improvement driving site stability and performance at scale.


