How to Validate Exact String or Number Length with Yup: Ensuring Exactly 5 Characters (e.g., Zip Codes)
In web development, validating user input is critical to ensuring data integrity, usability, and security. One common validation requirement is enforcing an exact length for strings or numbers—for example, U.S. zip codes (5 digits), postal codes, product IDs, or access codes. Manually writing validation logic for this can be error-prone, but libraries like Yup simplify the process by providing a declarative, schema-based approach.
In this guide, we’ll dive deep into using Yup to validate exact string or number lengths, with a focus on 5-character values (e.g., zip codes). We’ll cover schema creation, edge cases, integration with form libraries like Formik, and common pitfalls to avoid. By the end, you’ll have a robust solution to enforce exact length validation in your applications.
Table of Contents#
- What is Yup?
- Why Exact Length Validation Matters
- Prerequisites
- Step-by-Step Guide: Validate Exact 5 Characters with Yup
- Handling Edge Cases
- Integrating with Form Libraries (e.g., Formik)
- Common Pitfalls and Solutions
- Conclusion
- References
What is Yup?#
Yup is a popular JavaScript schema builder for value validation. It allows you to define validation rules (schemas) for strings, numbers, objects, arrays, and more in a readable, chainable syntax. Yup is widely used with form libraries like Formik and React Hook Form to streamline form validation, but it works standalone too.
At its core, Yup lets you:
- Define rules (e.g., "this field must be a string with exactly 5 characters").
- Generate user-friendly error messages.
- Validate values synchronously or asynchronously.
Why Exact Length Validation Matters#
Exact length validation ensures inputs meet strict format requirements, which is critical for:
- Data Integrity: Fields like zip codes (U.S.), postal codes (e.g., Canada’s 6-character alphanumeric codes), or SMS verification codes (often 4-6 digits) rely on fixed lengths to be valid.
- User Experience: Clear validation prevents users from submitting invalid data (e.g., a 4-digit zip code) and provides immediate feedback.
- Backend Compatibility: Many APIs or databases enforce fixed-length constraints (e.g., a
VARCHAR(5)column for zip codes). Frontend validation reduces failed API calls.
Prerequisites#
Before diving in, ensure you have:
- Basic knowledge of JavaScript/TypeScript.
- Node.js and npm/yarn installed (to install Yup).
- (Optional) Familiarity with form libraries like Formik (for the integration section).
Install Yup via npm or yarn:
npm install yup # or yarn add yupStep-by-Step Guide: Validate Exact 5 Characters with Yup#
1. Creating a Basic Yup Schema#
Yup schemas start by defining the type of value you want to validate (e.g., string(), number(), object()). For zip codes, we’ll focus on strings (since numbers can lose leading zeros, e.g., "01234" is a valid zip code but 01234 as a number becomes 1234).
Let’s start with a simple string schema:
import * as Yup from 'yup';
// Define a schema for a zip code (string type)
const zipCodeSchema = Yup.string();2. Using .length() for Exact Length Validation#
Yup’s string() schema includes a .length() method to enforce an exact length. The syntax is:
string().length(exactLength, errorMessage)exactLength: The required length (e.g.,5for zip codes).errorMessage: Custom message if validation fails (optional, but recommended for clarity).
Example: Zip Code Schema with Exact Length
const zipCodeSchema = Yup.string()
.length(5, 'Zip code must be exactly 5 characters long') // Enforce 5-character length
.required('Zip code is required'); // Optional: Make the field required3. Validating the Schema#
Now, test the schema with valid and invalid values using Yup’s validation methods:
Validate Synchronously with validateSync()#
// Valid value: 5 characters
const validZip = '12345';
try {
zipCodeSchema.validateSync(validZip);
console.log('Valid!'); // Output: "Valid!"
} catch (error) {
console.error(error.message);
}
// Invalid value: 4 characters
const invalidZip = '1234';
try {
zipCodeSchema.validateSync(invalidZip);
} catch (error) {
console.error(error.message); // Output: "Zip code must be exactly 5 characters long"
}Validate Asynchronously with validate()#
For async workflows (e.g., form submission), use validate() (returns a promise):
const validateZip = async (zip) => {
try {
await zipCodeSchema.validate(zip);
return { isValid: true };
} catch (error) {
return { isValid: false, error: error.message };
}
};
validateZip('12345').then(result => console.log(result)); // { isValid: true }
validateZip('123').then(result => console.log(result)); // { isValid: false, error: "Zip code must be exactly 5 characters long" }Validating Strings vs. Numbers#
What if you need to validate a number (e.g., a 5-digit ID)? Yup’s number() schema doesn’t have a direct .length() method, but you can convert the number to a string first using .transform():
const numericIdSchema = Yup.number()
.transform((value) => String(value)) // Convert number to string
.length(5, 'ID must be exactly 5 digits')
.required('ID is required');
// Test:
numericIdSchema.validateSync(12345); // Valid (string "12345" has length 5)
numericIdSchema.validateSync(1234); // Invalid (string "1234" has length 4)⚠️ Caveat: Numbers with leading zeros (e.g., 01234) will be parsed as 1234 (a 4-digit number), so the transformed string will be "1234" (length 4). For values requiring leading zeros (e.g., "01234"), always use strings instead of numbers.
Handling Edge Cases#
Even with .length(5), edge cases can break validation. Let’s address common issues:
Trimming Whitespace#
Users might accidentally add spaces (e.g., " 1234" or "1234 "). These would have a length of 5 but are invalid. Use .trim() to remove leading/trailing whitespace before validating length:
const zipCodeSchema = Yup.string()
.trim() // Remove leading/trailing spaces
.length(5, 'Zip code must be exactly 5 characters (excluding spaces)')
.required('Zip code is required');
// Test:
zipCodeSchema.validateSync(' 1234 '); // Invalid (trimmed to "1234", length 4)
zipCodeSchema.validateSync(' 12345 '); // Valid (trimmed to "12345", length 5)Rejecting Non-Digit Characters (e.g., Zip Codes)#
A 5-character string like "12A34" has the correct length but isn’t a valid zip code (U.S. zip codes are digits only). Add .matches() with a regex to enforce numeric characters:
const zipCodeSchema = Yup.string()
.trim()
.length(5, 'Zip code must be exactly 5 characters')
.matches(/^\d+$/, 'Zip code must contain only digits (0-9)') // Regex: only digits
.required('Zip code is required');
// Test:
zipCodeSchema.validateSync('12A34'); // Invalid: "Zip code must contain only digits (0-9)"
zipCodeSchema.validateSync('12345'); // ValidHandling Empty Values or null#
If the field is optional, remove .required() to allow null or undefined. Yup will skip validation for empty values by default:
const optionalZipSchema = Yup.string()
.trim()
.length(5, 'Zip code must be exactly 5 characters')
.nullable(); // Allow null/undefined
optionalZipSchema.validateSync(null); // Valid (no error)
optionalZipSchema.validateSync(''); // Valid (empty string)
optionalZipSchema.validateSync('123'); // Invalid: "Zip code must be exactly 5 characters"Integrating with Form Libraries (e.g., Formik)#
Yup pairs seamlessly with Formik, a popular React form library. Let’s build a zip code input form with real-time validation:
Step 1: Install Formik#
npm install formik # or yarn add formikStep 2: Create a Form with Formik and Yup#
import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
// Define the Yup schema
const ZipCodeFormSchema = Yup.object().shape({
zipCode: Yup.string()
.trim()
.length(5, 'Zip code must be exactly 5 characters')
.matches(/^\d+$/, 'Zip code must contain only digits')
.required('Zip code is required'),
});
const ZipCodeForm = () => {
return (
<div>
<h1>Enter Your Zip Code</h1>
<Formik
initialValues={{ zipCode: '' }} // Initial empty value
validationSchema={ZipCodeFormSchema} // Use the Yup schema
onSubmit={(values) => {
alert(`Valid zip code submitted: ${values.zipCode}`);
}}
>
{({ isSubmitting }) => (
<Form>
{/* Zip Code Input */}
<div>
<label htmlFor="zipCode">Zip Code:</label>
<Field type="text" name="zipCode" /> {/* "text" to preserve leading zeros */}
<ErrorMessage name="zipCode" component="div" style={{ color: 'red' }} />
</div>
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
</div>
);
};
export default ZipCodeForm;Key Points:
- Use
type="text"for the input to avoid numeric keyboard issues and preserve leading zeros. ErrorMessageautomatically displays Yup’s error messages when validation fails.- Formik handles real-time validation as the user types.
Common Pitfalls and Solutions#
| Pitfall | Solution |
|---|---|
Accidental whitespace causing false positives (e.g., " 1234"). | Use .trim() before .length() to remove spaces. |
Non-digit characters passing length validation (e.g., "12A34"). | Add .matches(/^\d+$/, 'Message') to enforce digits only. |
Using number type for values with leading zeros (e.g., "01234"). | Always use string type for inputs requiring leading zeros. |
| Vague error messages (e.g., "Invalid"). | Customize messages in .length() and .matches() for clarity (e.g., "Zip code must be 5 digits"). |
Conclusion#
Validating exact string or number lengths with Yup is straightforward once you understand the .length() method and how to handle edge cases like whitespace or non-digit characters. By combining Yup with form libraries like Formik, you can build robust, user-friendly forms that ensure data integrity.
Remember:
- Use
string().length(5, 'Message')for exact length validation. - Add
.trim()and.matches()to handle whitespace and invalid characters. - Prefer strings over numbers for values with leading zeros (e.g., zip codes).
References#
- Yup Official Documentation
- Formik Documentation
- MDN Web Docs: Regular Expressions
- U.S. Zip Code Format (for zip code validation context)