| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
The most comprehensive string validation package for Dart & Flutter.
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:
Zero runtime dependencies. Fully tested. Works with both Dart and Flutter.
Add the package to your pubspec.yaml:
dependencies:
flutter_validators: ^1.2.0Then run:
dart pub getImport 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; // trueAs top-level functions — handy when the value isn't a literal:
isEmail('foo@bar.com'); // true
isURL('https://google.com'); // true
isIP('192.168.1.1'); // trueAs Flutter form validators — drop straight into TextFormField:
TextFormField(
validator: Validator.email(errorMessage: 'Enter a valid email'),
)Every validator is available both as a top-level function and as a String extension. Parameterized validators accept their options as named/positional arguments.
| Validator | Extension | Description |
|---|---|---|
| isEmail(str) | str.isEmail | Valid email address |
| isURL(str) | str.isURL | Valid HTTP/HTTPS URL |
| isFQDN(str) | str.isFQDN | Fully qualified domain name |
| isPhone(str) | str.isPhone | Phone number (international & US formats) |
| isLatLong(str) | str.isLatLong | latitude,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| Validator | Extension | Description |
|---|---|---|
| isInt(str) | str.isInt | Integer (positive or negative) |
| isNumeric(str) | str.isNumeric | Number (integer or float) |
| isFloat(str, {min, max}) | str.isFloat({min, max}) | Finite float, optionally within a range |
| isDecimal(str) | str.isDecimal | Decimal number |
| isHexadecimal(str) | str.isHexadecimal | Hexadecimal number |
| isOctal(str) | str.isOctal | Octal number |
| isPort(str) | str.isPort | Port 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)| Validator | Extension | Description |
|---|---|---|
| isAlpha(str) | str.isAlpha | Letters only (a–z, A–Z) |
| isAlphanumeric(str) | str.isAlphanumeric | Letters and numbers only |
| isAscii(str) | str.isAscii | ASCII characters only |
| isLowercase(str) | str.isLowercase | Entirely lowercase |
| isUppercase(str) | str.isUppercase | Entirely 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.isSlug | URL 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'); // true
contains('Hello World', 'world', ignoreCase: true); // true
contains('a-a-a', 'a', minOccurrences: 3); // true| Validator | Extension | Description |
|---|---|---|
| isBase32(str) | str.isBase32 | Base32 encoded |
| isBase58(str) | str.isBase58 | Base58 encoded |
| isBase64(str, {urlSafe}) | str.isBase64({urlSafe}) | Base64 encoded (standard or URL-safe) |
| isJson(str) | str.isJson | Valid JSON |
| isHexColor(str) | str.isHexColor | Hex color code (#fff, ff0000) |
| isBoolean(str) | str.isBoolean | Boolean string (true/false/1/0) |
| isDate(str) | str.isDate | Parseable 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| Validator | Extension | Description |
|---|---|---|
| isUUID(str) | str.isUUID | UUID (v1, v3, v4, v5) |
| isMongoId(str) | str.isMongoId | MongoDB ObjectId (24-char hex) |
| isMD5(str) | str.isMD5 | MD5 hash |
| isJWT(str) | str.isJWT | JSON Web Token |
| isCreditCard(str) | str.isCreditCard | Credit card number (Luhn algorithm) |
| isMACAddress(str) | str.isMACAddress | MAC address (EUI-48 / EUI-64) |
| isSemVer(str) | str.isSemVer | Semantic 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| Validator | Extension | Description |
|---|---|---|
| isStrongPassword(str, {...}) | str.isStrongPassword({...}) | Password meets configurable strength rules |
isStrongPassword accepts five options, all with sensible defaults:
| Option | Default | Meaning |
|---|---|---|
| minLength | 8 | Minimum total length |
| minLowercase | 1 | Minimum lowercase letters |
| minUppercase | 1 | Minimum uppercase letters |
| minNumbers | 1 | Minimum digits |
| minSymbols | 1 | Minimum 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,
); // trueSanitizers 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';| Sanitizer | Extension | Description |
|---|---|---|
| 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'| Sanitizer | Extension | Description |
|---|---|---|
| escape(str) | str.escape() | Escape HTML-unsafe characters |
| unescape(str) | str.unescape() | Reverse of escape |
escape('<script>alert(1)</script>');
// '<script>alert(1)</script>'
unescape('<b>hi</b>'); // '<b>hi</b>'| Sanitizer | Extension | Description |
|---|---|---|
| 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'| Sanitizer | Extension | Returns | Description |
|---|---|---|---|
| toBoolean(str, {strict}) | str.toBoolean({strict}) | bool | Convert 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'); // true
toBoolean('0'); // false
toBoolean('yes', strict: true); // false (strict: only '1'/'true' are true)
toInt('42'); // 42
toInt('ff', radix: 16); // 255
toInt('abc'); // null
toFloat('3.14'); // 3.14
toDate('2024-01-15'); // DateTime(2024, 1, 15)| Sanitizer | Extension | Returns | Description |
|---|---|---|---|
| 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'); // nullThe 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';
class SignUpForm extends StatefulWidget {
const SignUpForm({super.key});
@override
State<SignUpForm> createState() => _SignUpFormState();
}
class _SignUpFormState extends State<SignUpForm> {
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
// Combine `required` with `email` to enforce a non-empty, valid email.
TextFormField(
decoration: const InputDecoration(labelText: 'Email'),
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) {
return Validator.required(errorMessage: 'Email is required')(value) ??
Validator.email(errorMessage: 'Enter a valid email')(value);
},
),
TextFormField(
decoration: const InputDecoration(labelText: 'Website'),
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: Validator.url(),
),
TextFormField(
decoration: const InputDecoration(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(
const SnackBar(content: Text('Form is valid!')),
);
}
},
child: const Text('Sign Up'),
),
],
),
);
}
}A complete, runnable app is in the example/ directory.
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})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) {
return Validator.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.
Contributions, issues, and feature requests are welcome! Feel free to check the issues page.
This project is MIT licensed.
| Back | FazBrowse Home | New Git URL |