Skip to content

Repository files navigation

Flutter Validators Banner

Flutter Validators

The most comprehensive string validation package for Dart & Flutter.

Pub VersionCIMIT LicenseStars

Inspired by validator.js · 40+ validators & sanitizers · Works with Flutter Forms out of the box


Flutter Validators is a pure Dart package with 40+ string validators and 13 sanitizers — from emails and URLs to credit cards, UUIDs, JWTs and strong-password checks. Every validator works three ways:

  • as a top-level functionisEmail('foo@bar.com')
  • as a String extension'foo@bar.com'.isEmail
  • as a Flutter form validatorValidator.email() plugs straight into TextFormField

Zero runtime dependencies. Fully tested. Works with both Dart and Flutter.


📚 Table of Contents


✨ Features

  • 40+ validators covering email, URL, numbers, encodings, identifiers, crypto hashes and more.
  • 13 sanitizers for trimming, HTML escaping, character filtering and type conversion.
  • Three usage styles — top-level functions, String extensions, and Flutter form validators — pick whatever reads best.
  • First-class Flutter form support via the Validator class, which returns String? Function(String?) closures with customizable error messages.
  • Pure Dart, zero runtime dependencies — lightweight and safe to add to any project.
  • Fully tested — every validator and sanitizer has dedicated test coverage.

📦 Installation

Add the package to your pubspec.yaml:

dependencies:
flutter_validators: ^1.2.0

Then run:

dart pub get

🚀 Quick Start

Import the package:

import'package:flutter_validators/flutter_validators.dart';

As String extensions — the most concise style:

'foo@bar.com'.isEmail; // true'https://google.com'.isURL; // true'4111111111111111'.isCreditCard; // true'abc123'.isAlphanumeric; // true

As top-level functions — handy when the value isn't a literal:

isEmail('foo@bar.com'); // trueisURL('https://google.com'); // trueisIP('192.168.1.1'); // true

As Flutter form validators — drop straight into TextFormField:

TextFormField(
validator:Validator.email(errorMessage:'Enter a valid email'),
)

🧩 Validators

Every validator is available both as a top-level function and as a String extension. Parameterized validators accept their options as named/positional arguments.

Contact and Web

ValidatorExtensionDescription
isEmail(str)str.isEmailValid email address
isURL(str)str.isURLValid HTTP/HTTPS URL
isFQDN(str)str.isFQDNFully qualified domain name
isPhone(str)str.isPhonePhone number (international & US formats)
isLatLong(str)str.isLatLonglatitude,longitude coordinate pair
'user@example.com'.isEmail; // true'https://dart.dev'.isURL; // true'sub.example.co.uk'.isFQDN; // true'localhost'.isFQDN; // false (no TLD)'(123) 456-7890'.isPhone; // true'40.7128,-74.0060'.isLatLong; // true

Numbers

ValidatorExtensionDescription
isInt(str)str.isIntInteger (positive or negative)
isNumeric(str)str.isNumericNumber (integer or float)
isFloat(str, {min, max})str.isFloat({min, max})Finite float, optionally within a range
isDecimal(str)str.isDecimalDecimal number
isHexadecimal(str)str.isHexadecimalHexadecimal number
isOctal(str)str.isOctalOctal number
isPort(str)str.isPortPort number (0–65535)
'42'.isInt; // true'3.14'.isNumeric; // true'1.5'.isFloat(); // true'5'.isFloat(min:0, max:2); // false (out of range)'.5'.isDecimal; // true'deadBEEF'.isHexadecimal; // true'0o17'.isOctal; // true'8080'.isPort; // true'65536'.isPort; // false (out of range)

Text and Format

ValidatorExtensionDescription
isAlpha(str)str.isAlphaLetters only (a–z, A–Z)
isAlphanumeric(str)str.isAlphanumericLetters and numbers only
isAscii(str)str.isAsciiASCII characters only
isLowercase(str)str.isLowercaseEntirely lowercase
isUppercase(str)str.isUppercaseEntirely uppercase
isLength(str, min, [max])str.isLength(min, [max])Length within a range
isByteLength(str, min, [max])str.isByteLength(min, [max])UTF-8 byte length within a range
isSlug(str)str.isSlugURL slug (my-blog-post)
isIn(str, values)str.isIn(values)One of an allowed set of values
matches(str, pattern)str.matches(pattern)Matches a Pattern / RegExp
contains(str, seed, {ignoreCase, minOccurrences})Contains a substring
equals(str, comparison)str.equals(comparison)Exact (case-sensitive) string match
'Hello'.isAlpha; // true'abc123'.isAlphanumeric; // true'héllo'.isAscii; // false'hello'.isLowercase; // true'abc'.isLength(2, 5); // true'é'.isByteLength(2, 2); // true ('é' is 2 bytes in UTF-8)'my-blog-post'.isSlug; // true'red'.isIn(['red', 'green', 'blue']); // true'abc123'.matches(RegExp(r'\d+')); // true'foo'.equals('foo'); // true// `contains` is a top-level function only (see Behavior Notes)contains('hello world', 'world'); // truecontains('Hello World', 'world', ignoreCase:true); // truecontains('a-a-a', 'a', minOccurrences:3); // true

Encoding and Data

ValidatorExtensionDescription
isBase32(str)str.isBase32Base32 encoded
isBase58(str)str.isBase58Base58 encoded
isBase64(str, {urlSafe})str.isBase64({urlSafe})Base64 encoded (standard or URL-safe)
isJson(str)str.isJsonValid JSON
isHexColor(str)str.isHexColorHex color code (#fff, ff0000)
isBoolean(str)str.isBooleanBoolean string (true/false/1/0)
isDate(str)str.isDateParseable date string
'JBSWY3DP'.isBase32; // true'aGVsbG8='.isBase64(); // true'a-b_cdef'.isBase64(urlSafe:true); // true'{"name":"Dart"}'.isJson; // true'#ff0000'.isHexColor; // true'true'.isBoolean; // true'2024-01-15'.isDate; // true

Identifiers and Crypto

ValidatorExtensionDescription
isUUID(str)str.isUUIDUUID (v1, v3, v4, v5)
isMongoId(str)str.isMongoIdMongoDB ObjectId (24-char hex)
isMD5(str)str.isMD5MD5 hash
isJWT(str)str.isJWTJSON Web Token
isCreditCard(str)str.isCreditCardCredit card number (Luhn algorithm)
isMACAddress(str)str.isMACAddressMAC address (EUI-48 / EUI-64)
isSemVer(str)str.isSemVerSemantic version
'550e8400-e29b-41d4-a716-446655440000'.isUUID; // true'507f1f77bcf86cd799439011'.isMongoId; // true'd41d8cd98f00b204e9800998ecf8427e'.isMD5; // true'eyJhbGci.eyJzdWIi.SflKxwRJ'.isJWT; // true'4111111111111111'.isCreditCard; // true'00:1B:44:11:3A:B7'.isMACAddress; // true'2.1.0-alpha.1'.isSemVer; // true

Security

ValidatorExtensionDescription
isStrongPassword(str, {...})str.isStrongPassword({...})Password meets configurable strength rules

isStrongPassword accepts five options, all with sensible defaults:

OptionDefaultMeaning
minLength8Minimum total length
minLowercase1Minimum lowercase letters
minUppercase1Minimum uppercase letters
minNumbers1Minimum digits
minSymbols1Minimum non-alphanumeric symbols
'Abcd1234!'.isStrongPassword(); // true'weak'.isStrongPassword(); // false// Relax the rules — e.g. allow passphrases with no symbols or digits'abcdefghij'.isStrongPassword(
minUppercase:0,
minNumbers:0,
minSymbols:0,
); // true

🧹 Sanitizers

Sanitizers transform or coerce strings. Like validators, they're available as both top-level functions and String extensions. Import them via the main library or directly:

import'package:flutter_validators/flutter_validators.dart';
// or, sanitizers only:import'package:flutter_validators/sanitizers.dart';

Trimming

SanitizerExtensionDescription
trim(str, [chars])str.trimChars(chars)Trim whitespace/chars from both ends
ltrim(str, [chars])str.ltrimChars(chars)Trim from the start
rtrim(str, [chars])str.rtrimChars(chars)Trim from the end
trim(' hello '); // 'hello'trim('xxhelloxx', 'x'); // 'hello'ltrim('00042', '0'); // '42'rtrim('hello!!!', '!'); // 'hello'

HTML Escaping

SanitizerExtensionDescription
escape(str)str.escape()Escape HTML-unsafe characters
unescape(str)str.unescape()Reverse of escape
escape('<script>alert(1)</script>');
// '&lt;script&gt;alert(1)&lt;&#x2F;script&gt;'unescape('&lt;b&gt;hi&lt;&#x2F;b&gt;'); // '<b>hi</b>'

Character Filtering

SanitizerExtensionDescription
blacklist(str, chars)str.blacklist(chars)Remove the listed characters
whitelist(str, chars)str.whitelist(chars)Keep only the listed characters
stripLow(str, {keepNewLines})str.stripLow({keepNewLines})Remove ASCII control characters
blacklist('hello world', 'lo'); // 'he wrd'whitelist('a1b2c3', '0123456789'); // '123'stripLow('line1\nline2'); // 'line1line2'stripLow('line1\nline2', keepNewLines:true); // 'line1\nline2'

Type Conversion

SanitizerExtensionReturnsDescription
toBoolean(str, {strict})str.toBoolean({strict})boolConvert to a boolean
toInt(str, {radix})str.toInt({radix})int?Parse to an integer
toFloat(str)str.toFloat()double?Parse to a double
toDate(str)str.toDate()DateTime?Parse to a DateTime
toBoolean('true'); // truetoBoolean('0'); // falsetoBoolean('yes', strict:true); // false (strict: only '1'/'true' are true)toInt('42'); // 42toInt('ff', radix:16); // 255toInt('abc'); // nulltoFloat('3.14'); // 3.14toDate('2024-01-15'); // DateTime(2024, 1, 15)

Email Normalization

SanitizerExtensionReturnsDescription
normalizeEmail(str)str.normalizeEmail()String?Canonicalize an email address
normalizeEmail('Test.User+promo@GMAIL.com'); // 'testuser@gmail.com'normalizeEmail('User@Example.COM'); // 'User@example.com'normalizeEmail('not-an-email'); // null

📝 Flutter Form Integration

The Validator class returns String? Function(String?) closures — exactly the type TextFormField.validator expects. A closure returns null when the value is valid, or the error message when it isn't. Every method accepts a custom errorMessage.

import'package:flutter/material.dart';
import'package:flutter_validators/flutter_validators.dart';
classSignUpFormextendsStatefulWidget {
constSignUpForm({super.key});
@overrideState<SignUpForm> createState() =>_SignUpFormState();
}
class_SignUpFormStateextendsState<SignUpForm> {
final _formKey =GlobalKey<FormState>();
@overrideWidgetbuild(BuildContext context) {
returnForm(
key: _formKey,
child:Column(
children: [
// Combine `required` with `email` to enforce a non-empty, valid email.TextFormField(
decoration:constInputDecoration(labelText:'Email'),
autovalidateMode:AutovalidateMode.onUserInteraction,
validator: (value) {
returnValidator.required(errorMessage:'Email is required')(value) ??Validator.email(errorMessage:'Enter a valid email')(value);
},
),
TextFormField(
decoration:constInputDecoration(labelText:'Website'),
autovalidateMode:AutovalidateMode.onUserInteraction,
validator:Validator.url(),
),
TextFormField(
decoration:constInputDecoration(labelText:'Password'),
obscureText:true,
autovalidateMode:AutovalidateMode.onUserInteraction,
validator:Validator.strongPassword(
errorMessage:'Use 8+ chars with upper, lower, number & symbol',
),
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
ScaffoldMessenger.of(context).showSnackBar(
constSnackBar(content:Text('Form is valid!')),
);
}
},
child:constText('Sign Up'),
),
],
),
);
}
}

A complete, runnable app is in the example/ directory.

Validator API Reference

Every method on the Validator class returns String? Function(String?):

Validator.required({String errorMessage})
Validator.email({String errorMessage})
Validator.url({String errorMessage})
Validator.ip({int? version, String errorMessage})
Validator.fqdn({String errorMessage})
Validator.phone({String errorMessage})
Validator.latLong({String errorMessage})
Validator.date({String errorMessage})
Validator.numeric({String errorMessage})
Validator.integer({String errorMessage})
Validator.float({double? min, double? max, String errorMessage})
Validator.decimal({String errorMessage})
Validator.hexadecimal({String errorMessage})
Validator.octal({String errorMessage})
Validator.port({String errorMessage})
Validator.alpha({String errorMessage})
Validator.alphanumeric({String errorMessage})
Validator.ascii({String errorMessage})
Validator.lowercase({String errorMessage})
Validator.uppercase({String errorMessage})
Validator.slug({String errorMessage})
Validator.length(int min, {int? max, String errorMessage})
Validator.byteLength(int min, {int? max, String errorMessage})
Validator.contains(String seed, {bool ignoreCase, int minOccurrences, String errorMessage})
Validator.matches(Pattern pattern, {String errorMessage})
Validator.inList(Iterable<String> allowed, {String errorMessage})
Validator.equals(String comparison, {String errorMessage})
Validator.base32({String errorMessage})
Validator.base58({String errorMessage})
Validator.base64({bool urlSafe, String errorMessage})
Validator.json({String errorMessage})
Validator.hexColor({String errorMessage})
Validator.boolean({String errorMessage})
Validator.uuid({String errorMessage})
Validator.mongoId({String errorMessage})
Validator.md5({String errorMessage})
Validator.jwt({String errorMessage})
Validator.creditCard({String errorMessage})
Validator.macAddress({String errorMessage})
Validator.semVer({String errorMessage})
Validator.strongPassword({int minLength, int minLowercase, int minUppercase, int minNumbers, int minSymbols, String errorMessage})

💡 Behavior Notes and FAQ

Validator methods treat null and empty strings as valid. This is intentional — it lets you compose validators freely. To make a field mandatory, pair it with Validator.required():

validator: (value) {
returnValidator.required()(value) ??Validator.email()(value);
}

contains is a top-level function only. Dart's String already has a built-in .contains() method, so the package does not add a conflicting extension. Use contains(str, seed) instead of str.contains(...) when you need the case-insensitivity or minOccurrences options.

Trimming extensions are named trimChars / ltrimChars / rtrimChars. Dart's String already provides .trim(), .trimLeft() and .trimRight() for whitespace, so the custom-character variants use distinct names to avoid collisions. The top-level functions keep the plain trim / ltrim / rtrim names.

isURL accepts only http and https schemes. Other schemes such as ftp:// are rejected.

isBase64 has a urlSafe option. By default it validates the standard Base64 alphabet (with padding); pass urlSafe: true to validate the URL- and filename-safe alphabet instead.

isBoolean accepts 'true', 'false', '1' and '0'. Any other value is not a boolean string.

isFloat rejects non-finite values.'Infinity' and 'NaN' return false, even though Dart's double.tryParse can parse them.

normalizeEmail applies Gmail-specific rules. For gmail.com / googlemail.com addresses it lowercases the local part, removes dots, and strips any +tag suffix. For other providers it only lowercases the domain. It returns null if the input isn't a valid email.


🤝 Contributing

Contributions, issues, and feature requests are welcome! Feel free to check the issues page.


📄 License

This project is MIT licensed.

About

A comprehensive, lightweight Dart & Flutter validation library with 40+ validators and 13 sanitizers. Supports top-level functions, String extensions, and seamless Flutter Form integration.

Topics

Resources

Stars

8 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages