โ X Validators
The simplest way to validate Flutter form fields โ a small, composable set of rules
that plug straight into any TextFormField.validator.
- โ Zero dependencies โ pure Dart, nothing to ship but your code
- ๐งฉ Composable โ stack rules; the first failure wins
- ๐ Extensible โ write your own rule by implementing one method
- ๐ Localizable โ translate every error message per rule type
- ๐งช Well tested โ every rule is covered by unit tests
Table of Contents
๐ Installation
Add the dependency to your pubspec.yaml:
dependencies:
x_validators: ^1.1.0
Then run flutter pub get (or dart pub get).
import 'package:x_validators/x_validators.dart';
โก Quick start
xValidator takes a list of rules and returns a String? Function(String?) โ
exactly the signature Flutter's form fields expect:
TextFormField(
decoration: const InputDecoration(labelText: 'Email'),
validator: xValidator([
const IsRequired(),
const IsEmail(),
]),
);
The returned function yields null when the value is valid, or the error message
of the first failing rule otherwise.
๐ง How it works
Every rule is a small class that extends TextXValidationRule and answers one
question โ bool isValid(String input). xValidator runs the rules in order
and stops at the first one that fails:
xValidator([ ruleโ, ruleโ, ruleโ ]) โโโถ String? Function(String? value)
โ
value โโถ ruleโ.isValid? โ yes โโถ ruleโ.isValid? โ yes โโถ ruleโ ... โโถ null (valid)
โ no โ no
โผ โผ
error message error message (first failure wins)
Because order matters, put broad rules first (e.g. IsRequired) and specific
rules after (e.g. IsEmail).
๐ API reference
All rules accept an optional positional error message as their last
argument (e.g. IsRequired('This field is required')). When omitted, the rule's
default message is used (see Localizing error messages).
Text
| Rule | Description |
|---|---|
IsRequired([error]) |
Fails when the trimmed input is empty. |
IsEmpty([error]) |
Passes only when the trimmed input is empty. |
Contains(value, [error]) |
Input contains value (compared after trimming). |
NotContains(value, [error]) |
Input does not contain value. |
StartsWith(prefix, [error]) |
Input starts with prefix. |
EndsWith(suffix, [error]) |
Input ends with suffix. |
Match(value, {caseSensitive = true}, [error]) |
Input equals value; case-insensitive when caseSensitive is false. |
MinLength(min, [error]) |
Trimmed length is >= min. |
MaxLength(max, [error]) |
Trimmed length is <= max. |
Numbers
| Rule | Description |
|---|---|
IsNumber([error]) |
Input is a number. |
IsArabicNum([error]) |
Positive integer written in Latin digits 0-9 (no leading zero). |
IsHindiNum([error]) |
Number written in Arabic-Indic digits ู -ูฉ. |
MinValue(min, [error]) |
Parsed numeric value is >= min. |
MaxValue(max, [error]) |
Parsed numeric value is <= max. |
URLs
| Rule | Description |
|---|---|
IsUrl([error]) |
Input is a valid http/https URL. |
IsSecureUrl([error]) |
Input is a URL using the https:// scheme. |
IsFacebookUrl([error]) |
Input is a valid Facebook URL. |
IsInstagramUrl([error]) |
Input is a valid Instagram URL. |
IsYoutubeUrl([error]) |
Input is a valid YouTube URL. |
Phone
| Rule | Description |
|---|---|
IsEgyptianPhone([error]) |
Input is a valid Egyptian phone number. |
ISKsaPhone([error]) |
Input is a valid Saudi Arabian phone number. |
IT
| Rule | Description |
|---|---|
IsEmail([error]) |
Input is a valid email address. |
IsBool([error]) |
Input is a valid boolean value. |
IsIpAddress([error]) |
Input is a valid IP address. |
IsPort([error]) |
Input is a valid port number. |
RegExpRule(regExp, [error]) |
Input matches the provided RegExp. |
Lists
| Rule | Description |
|---|---|
IsIn(values, [error]) |
Input is one of the values in the provided list. |
IsNotIn(values, [error]) |
Input is not in the provided list. |
ContainsAny(values, [error]) |
Input contains at least one item from the list. |
NotContainsAny(values, [error]) |
Input contains none of the items in the list. |
Dates
| Rule | Description |
|---|---|
IsDate([error]) |
Input is a parseable date string. |
IsDateMillis([error]) |
Input is an integer of milliseconds since epoch. |
IsDateAfter(date, [error]) |
Input is a date later than date. |
Languages
| Rule | Description |
|---|---|
IsArabicChars([error]) |
Input consists of Arabic characters. |
IsEnglishChars([error]) |
Input consists of English (ASCII) characters. |
IsNumbersOnly([error]) |
Input contains digits. |
IsLtrLanguage([error]) |
Input is a left-to-right language code. |
IsRTLLanguage([error]) |
Input is a right-to-left language code. |
Colors
| Rule | Description |
|---|---|
IsHexColor([error]) |
Input is a valid 3/6/8-digit hex color. |
Magic
| Rule | Description |
|---|---|
IsOptional() |
When present, an empty field skips all other rules and passes. |
๐ Usage guide
Composing rules
Rules run top-to-bottom and the first failure is returned, so order them from general to specific:
final validate = xValidator([
const IsRequired(), // checked first
const MinLength(8),
const MaxLength(32),
]);
validate(''); // โ IsRequired's message
validate('abc'); // โ MinLength's message
validate('hunter2!'); // โ null (valid)
Custom error messages
Pass a message as the rule's last argument to override its default:
xValidator([
const IsRequired('Please enter a value'),
const MinLength(8, 'Use at least 8 characters'),
]);
Reacting to failures (onFailureCallBack)
Useful for analytics or logging. The callback receives the input, the full rule list, and the rule that failed:
xValidator(
[
const IsRequired('Field cannot be empty'),
const MinLength(3, 'At least 3 characters'),
const MaxLength(20, 'At most 20 characters'),
],
onFailureCallBack: (input, rules, failedRule) {
debugPrint('Validation failed for "$input" on ${failedRule.runtimeType}');
},
);
Optional fields
Add IsOptional to let an empty field pass while still validating non-empty
input. Here an empty value is accepted, but anything typed must be a valid email:
xValidator([
const IsOptional(),
const IsEmail(),
]);
Writing a custom rule
Extend TextXValidationRule, implement isValid, and (optionally) override
toString() to provide a default message:
class StartsWithCapital extends TextXValidationRule {
const StartsWithCapital([super.error]);
@override
bool isValid(String input) =>
input.isNotEmpty && input[0] == input[0].toUpperCase();
@override
String toString() => 'Must start with a capital letter';
}
// Use it like any built-in rule:
xValidator([const StartsWithCapital()]);
Localizing error messages
Register a translator per rule type with XValidatorsLocalization.on<T>().
When that rule fails (and no inline error was given), your function supplies
the message:
XValidatorsLocalization.on<IsRequired>((rule) => 'ูุฐุง ุงูุญูู ู
ุทููุจ');
XValidatorsLocalization.on<IsEmail>((rule) => 'ุงูุจุฑูุฏ ุงูุฅููุชุฑููู ุบูุฑ ุตุงูุญ');
final validate = xValidator([const IsRequired()]);
validate(''); // โ 'ูุฐุง ุงูุญูู ู
ุทููุจ'
Resolution order for a failing rule is: inline error โ registered
translator โ rule.toString().
Standalone helper functions
Each rule also ships a top-level function for one-off checks outside of a form, mirroring the rule's logic:
isNotEmpty('hello'); // true
isEmpty(' '); // true
minLength('abc', 3); // true
EmailXValidator.validate('test@example.com'); // true
โน๏ธ Good to know
- A
nullvalue passed to the validator is currently treated as valid (it short-circuits tonull). In practice Flutter'sTextFormFieldpasses an empty string''rather thannull, whichIsRequiredrejects as expected. Treatingnullas empty is planned for the next major release.
๐ค Contributing
Issues and pull requests are welcome. Please run dart analyze and dart test
before opening a PR.
๐ License
See LICENSE.
๐จ๐ปโ๐ป Authors
Libraries
- core/utils/language_utils
- email_validator
- rules/colors/is_hex_color
- rules/dates/date_after
- rules/dates/is_date
- rules/dates/is_date_mills
- rules/index
- A library that provides a collection of text validation rules for various purposes.
- rules/it/is_boolean
- rules/it/is_email
- rules/it/is_ip_address
- rules/it/is_port
- rules/it/regx
- rules/languages/is_arabic_chars
- rules/languages/is_english_char
- rules/languages/is_ltr_language
- rules/languages/is_number_only
- rules/languages/is_rtl_language
- rules/lists/contains_any
- rules/lists/is_in
- rules/lists/is_not_in
- rules/lists/not_contains_any
- rules/magic/is_optional
- rules/numbers/is_arabic_num
- rules/numbers/is_hindi_num
- rules/numbers/is_number
- rules/numbers/max_value
- rules/numbers/min_value
- rules/phone/is_egy_number
- rules/phone/is_ksa_number
- rules/text/contains
- rules/text/ends_with
- rules/text/is_empty
- rules/text/is_not_empty
- rules/text/match
- rules/text/max_length
- rules/text/min_length
- rules/text/not_contains
- rules/text/starts_with
- rules/urls/is_facebook_url
- rules/urls/is_instgram_url
- rules/urls/is_secure_url
- rules/urls/is_url
- rules/urls/is_youtube_url
- text_rule_class
- tr
- validator
- x_validators
- A library that provides a collection of text validation utilities.
