Flutter Validators Banner

Flutter Validators

The most comprehensive string validation package for Dart & Flutter.

Pub Version CI MIT License Stars

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');     // true
isURL('https://google.com'); // true
isIP('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

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

Numbers

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)

Text and Format

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

Encoding and Data

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

Identifiers and Crypto

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

Security

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,
); // 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

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'

HTML Escaping

Sanitizer Extension Description
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

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'

Type Conversion

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)

Email Normalization

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');              // 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';

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.

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) {
  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.


🤝 Contributing

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


📄 License

This project is MIT licensed.