Validator is a modern, lightweight Swift framework that provides elegant and type-safe input validation. Built with Swift's powerful type system, it seamlessly integrates with both UIKit and SwiftUI, making form validation effortless across all Apple platforms.
β¨ Type-Safe Validation - Leverages Swift's type system for compile-time safety
π― Rich Rule Set - Built-in validators for common use cases
π§ Extensible - Easy to create custom validation rules
π± UIKit Integration - First-class support for UITextField and other UIKit components
π¨ SwiftUI Native - Property wrappers and view modifiers for declarative validation
π Form Management - Validate multiple fields with centralized state management
β‘ Lightweight - Minimal footprint with zero dependencies
π§ͺ Well Tested - Comprehensive test coverage
- Requirements
- Installation
- Quick Start
- Usage
- Built-in Validators
- Custom Validators
- Examples
- Communication
- Contributing
- License
| Platform | Minimum Version |
|---|---|
| iOS | 16.0+ |
| macOS | 13.0+ |
| tvOS | 16.0+ |
| watchOS | 9.0+ |
| visionOS | 1.0+ |
| Xcode | 15.3+ |
| Swift | 5.10+ |
The package contains two libraries: ValidatorCore encompasses all validation logic and predefined validators, while ValidatorUI implements extensions for integrating the validator into UI objects. It supports both SwiftUI and UIKit.
Add the following dependency to your Package.swift:
dependencies: [
.package(url: "https://github.com/space-code/validator.git", from: "1.2.0")
]Or add it through Xcode:
- File > Add Package Dependencies
- Enter package URL:
https://github.com/space-code/validator.git - Select version requirements
import ValidatorCore
let validator = Validator()
let result = validator.validate(
input: "[email protected]",
rule: RegexValidationRule(
pattern: "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}",
error: "Invalid email address"
)
)
switch result {
case .valid:
print("β
Valid input")
case .invalid(let errors):
print("β Validation failed: \(errors.map(\.message))")
}The framework provides two main libraries:
- ValidatorCore - Core validation logic and predefined validators
- ValidatorUI - UI integration for UIKit and SwiftUI
Validate any input with the Validator class:
import ValidatorCore
let validator = Validator()
let result = validator.validate(
input: "password123",
rule: LengthValidationRule(
min: 8,
error: "Password must be at least 8 characters"
)
)Import ValidatorUI to add validation to UIKit components:
import UIKit
import ValidatorUI
import ValidatorCore
class ViewController: UIViewController {
let emailField = UITextField()
override func viewDidLoad() {
super.viewDidLoad()
// Add validation rules
emailField.add(
rule: RegexValidationRule(
pattern: "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}",
error: "Please enter a valid email"
)
)
// Enable real-time validation
emailField.validateOnInputChange(isEnabled: true)
// Handle validation results
emailField.validationHandler = { result in
switch result {
case .valid:
self.updateUI(isValid: true)
case .invalid(let errors):
self.showErrors(errors)
}
}
}
}Use the .validation() modifier for simple field validation:
import SwiftUI
import ValidatorUI
import ValidatorCore
struct LoginView: View {
@State private var email = ""
var body: some View {
TextField("Email", text: $email)
.validation($email, rules: [
RegexValidationRule(
pattern: "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}",
error: "Invalid email"
)
]) { result in
if case .invalid(let errors) = result {
print("Validation errors: \(errors)")
}
}
}
}Or use .validate() with a custom error view:
struct LoginView: View {
@State private var password = ""
var body: some View {
VStack(alignment: .leading) {
SecureField("Password", text: $password)
.validate(item: $password, rules: [
LengthValidationRule(min: 8, error: "Too short")
]) { errors in
ForEach(errors, id: \.message) { error in
Text(error.message)
.foregroundColor(.red)
.font(.caption)
}
}
}
}
}Manage multiple fields with FormFieldManager:
import Combine
import SwiftUI
import ValidatorUI
import ValidatorCore
class RegistrationForm: ObservableObject {
@Published var manager = FormFieldManager()
@FormField(rules: [
LengthValidationRule(min: 2, max: 50, error: "Invalid name length")
])
var firstName = ""
@FormField(rules: [
LengthValidationRule(min: 2, max: 50, error: "Invalid name length")
])
var lastName = ""
@FormField(rules: [
RegexValidationRule(
pattern: "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}",
error: "Invalid email"
)
])
var email = ""
lazy var firstNameContainer = _firstName.validate(manager: manager)
lazy var lastNameContainer = _lastName.validate(manager: manager)
lazy var emailContainer = _email.validate(manager: manager)
}
struct RegistrationView: View {
@StateObject private var form = RegistrationForm()
@State private var isFormValid = false
var body: some View {
Form {
Section("Personal Information") {
TextField("First Name", text: $form.firstName)
.validate(validationContainer: form.firstNameContainer) { errors in
ErrorView(errors: errors)
}
TextField("Last Name", text: $form.lastName)
.validate(validationContainer: form.lastNameContainer) { errors in
ErrorView(errors: errors)
}
}
Section("Contact") {
TextField("Email", text: $form.email)
.validate(validationContainer: form.emailContainer) { errors in
ErrorView(errors: errors)
}
}
Section {
Button("Submit") {
form.manager.validate()
}
.disabled(!isFormValid)
}
}
.onReceive(form.manager.$isValid) { newValue in
isFormValid = newValue
}
}
private func submitForm() {
print("β
Form is valid, submitting...")
}
}| Validator | Description | Example |
|---|---|---|
LengthValidationRule |
Validates string length (min/max) | LengthValidationRule(min: 3, max: 20, error: "Length must be 3-20 characters") |
NonEmptyValidationRule |
Ensures string is not empty or blank | NonEmptyValidationRule(error: "Field is required") |
PrefixValidationRule |
Validates string prefix | PrefixValidationRule(prefix: "https://", error: "URL must start with https://") |
SuffixValidationRule |
Validates string suffix | SuffixValidationRule(suffix: ".com", error: "Domain must end with .com") |
RegexValidationRule |
Pattern matching validation | RegexValidationRule(pattern: "^\\d{3}-\\d{4}$", error: "Invalid phone format") |
URLValidationRule |
Validates URL format | URLValidationRule(error: "Please enter a valid URL") |
CreditCardValidationRule |
Validates credit card numbers (Luhn algorithm) | CreditCardValidationRule(error: "Invalid card number") |
EmailValidationRule |
Validates email format | EmailValidationRule(error: "Please enter a valid email") |
CharactersValidationRule |
Validates that a string contains only characters from the allowed CharacterSet | CharactersValidationRule(characterSet: .letters, error: "Invalid characters") |
NilValidationRule |
Validates that value is nil | NilValidationRule(error: "Value must be nil") |
Create custom validation rules by conforming to IValidationRule:
import ValidatorCore
struct EmailDomainValidationRule: IValidationRule {
typealias Input = String
let allowedDomains: [String]
let error: IValidationError
init(allowedDomains: [String], error: IValidationError) {
self.allowedDomains = allowedDomains
self.error = error
}
func validate(input: String) -> Bool {
guard let domain = input.split(separator: "@").last else {
return false
}
return allowedDomains.contains(String(domain))
}
}
// Usage
let rule = EmailDomainValidationRule(
allowedDomains: ["company.com", "company.org"],
error: "Only company email addresses are allowed"
)Combine multiple validators for complex validation logic:
// Define reusable validation rules
let lengthRule = LengthValidationRule(
min: 8,
max: 128,
error: "Password must be 8-128 characters"
)
let uppercaseRule = RegexValidationRule(
pattern: ".*[A-Z].*",
error: "Must contain uppercase letter"
)
let lowercaseRule = RegexValidationRule(
pattern: ".*[a-z].*",
error: "Must contain lowercase letter"
)
let numberRule = RegexValidationRule(
pattern: ".*[0-9].*",
error: "Must contain number"
)
let specialCharRule = RegexValidationRule(
pattern: ".*[!@#$%^&*(),.?\":{}|<>].*",
error: "Must contain special character"
)
// UIKit: Pass all rules to your text field
passwordField.add(rules: [
lengthRule,
uppercaseRule,
lowercaseRule,
numberRule,
specialCharRule
])
// SwiftUI: Use in validation modifier
SecureField("Password", text: $password)
.validation($password, rules: [
lengthRule,
uppercaseRule,
lowercaseRule,
numberRule,
specialCharRule
]) { result in
if case .invalid(let errors) = result {
self.passwordErrors = errors
}
}You can find usage examples in the Examples directory of the repository.
These examples demonstrate how to integrate the package, configure validation rules,
and build real-world user interfaces using ValidatorCore and ValidatorUI.
- π Found a bug? Open an issue
- π‘ Have a feature request? Open an issue
- β Questions? Start a discussion
- π Security issue? Email [email protected]
We love contributions! Please read our Contributing Guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes.
Bootstrap the development environment:
mise installThis project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.
Nikita Vasilev
- Email: [email protected]
- GitHub: @ns-vasilev
Validator is released under the MIT license. See LICENSE for details.
Made with β€οΈ by space-code
