π The most comprehensive form library for SwiftUI
Features β’ Installation β’ Quick Start β’ Field Types β’ Validation β’ Advanced
Building forms in SwiftUI can be tedious. You need validation, styling, accessibility, and state management - all from scratch. SwiftUI Forms Kit gives you everything out of the box:
| Feature | SwiftUI Forms Kit | Native SwiftUI | Other Libraries |
|---|---|---|---|
| 30+ Field Types | β | β | |
| Real-time Validation | β | β | |
| Async Validation | β | β | β |
| JSON-Driven Forms | β | β | β |
| Form Analytics | β | β | β |
| Multi-Step Forms | β | β | |
| Form DSL | β | β | β |
| Full Accessibility | β | ||
| Theming System | β | β |
Text Fields β Selection β Date & Time β Special
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β’ Text Input β β’ Dropdown β β’ Date Picker β β’ Signature
β’ Email β β’ Multi-Select β β’ Time Picker β β’ OTP Input
β’ Password β β’ Radio Buttons β β’ Date Range β β’ Credit Card
β’ Phone (Intl) β β’ Checkboxes β β’ Time Range β β’ Address
β’ URL β β’ Toggle β β’ Duration β β’ File Upload
β’ Number β β’ Chips β β β’ Image Picker
β’ Currency β β’ Segmented β β β’ Rating
β’ Textarea β β β β’ Slider
- Built-in rules: required, email, phone, minLength, maxLength, pattern
- Custom validators: Write your own validation logic
- Async validation: Check against APIs (username availability, etc.)
- Field dependencies: Validate based on other field values
- Real-time feedback: Instant error messages as users type
- Pre-built themes (Light, Dark, Minimal)
- Customize colors, spacing, corner radius
- Per-field style overrides
- Dark mode support
- Full VoiceOver support
- Dynamic Type support
- Reduce Motion support
- Screen reader announcements
dependencies: [
.package(url: "https://github.com/muhittincamdali/SwiftUI-Forms-Kit.git", from: "2.0.0")
]pod 'SwiftUIFormsKit', '~> 2.0'import SwiftUIFormsKit
struct LoginForm: View {
@State private var email = ""
@State private var password = ""
var body: some View {
FormContainer(title: "Sign In") {
FormTextField("Email", text: $email)
.keyboardType(.emailAddress)
.validation(.required, .email)
FormSecureField("Password", text: $password)
.validation(.required, .minLength(8))
SubmitButton("Sign In") {
// Handle login
}
}
}
}FormContainer(title: "Registration") {
FormSection("Personal Info") {
FormTextField("Full Name", text: $name)
.validation(.required)
FormPhoneField("Phone", phoneNumber: $phone, countryCode: $country)
FormDatePicker("Birth Date", selection: $birthDate)
}
FormSection("Account") {
FormTextField("Email", text: $email)
.validation(.required, .email)
FormSecureField("Password", text: $password, showStrengthIndicator: true)
.validation(.required, .strongPassword)
}
}// Standard text
FormTextField("Name", text: $name)
// Email with validation
FormTextField("Email", text: $email)
.keyboardType(.emailAddress)
.textContentType(.emailAddress)
.validation(.email)
// Password with strength indicator
FormSecureField("Password", text: $password, showStrengthIndicator: true)
// Phone with country picker
FormPhoneField("Phone", phoneNumber: $phone, countryCode: $country)
// Multiline text
FormTextField("Bio", text: $bio)
.lineLimit(5...10)// Single select dropdown
FormPicker("Country", selection: $country, options: countries)
// Multi-select with chips
FormMultiSelect("Skills", selection: $skills, options: allSkills, style: .chips)
// Radio buttons
FormRadioGroup("Plan", selection: $plan, options: [
RadioOption(value: "free", label: "Free", description: "Basic features"),
RadioOption(value: "pro", label: "Pro", description: "$9.99/month")
], style: .cards)
// Toggle
FormToggleField("Accept Terms", isOn: $acceptTerms, style: .checkbox)// Date picker
FormDatePicker("Birth Date", selection: $date)
// Time picker
FormTimePicker("Alarm", time: $time, style: .hourMinute)
// Time range
FormTimeRangePicker("Working Hours", startTime: $start, endTime: $end)// Rating
FormRatingField("Rate this app", rating: $rating, style: .stars)
// Slider with labels
FormSliderField("Budget", value: $budget, range: 0...1000, style: .labeled)
// Credit card
FormCreditCardField("Card", cardNumber: $card, expiryDate: $expiry, cvv: $cvv)
// Signature
FormSignatureField("Signature", signature: $signature)
// File upload
FormFileUpload("Documents", files: $files, allowedTypes: [.pdf, .image])
// OTP
FormOTPField("Verification Code", code: $otp, length: 6).validation(.required) // Must not be empty
.validation(.email) // Valid email format
.validation(.phone) // Valid phone number
.validation(.url) // Valid URL
.validation(.minLength(8)) // Minimum length
.validation(.maxLength(100)) // Maximum length
.validation(.min(18)) // Minimum value
.validation(.max(120)) // Maximum value
.validation(.pattern(#"^\d{5}$"#)) // Regex pattern
.validation(.creditCard) // Valid card number
.validation(.strongPassword) // Password strengthFormTextField("Username", text: $username)
.validation(.custom { value in
if value.contains(" ") {
return "Username cannot contain spaces"
}
return nil // Valid
})FormTextField("Username", text: $username)
.asyncValidation { value in
// Check if username is available
let isAvailable = await API.checkUsername(value)
return isAvailable ? nil : "Username already taken"
}FormSecureField("Confirm Password", text: $confirmPassword)
.validation(.matches(field: "password", message: "Passwords don't match"))MultiStepForm(state: formState, indicatorStyle: .numbered) {
FormStep("Personal", icon: "person") {
FormTextField("Name", text: $name)
FormTextField("Email", text: $email)
}
FormStep("Address", icon: "location") {
FormAddressField(address: $address)
}
FormStep("Payment", icon: "creditcard") {
FormCreditCardField("Card", cardNumber: $card, ...)
}
}let schema = """
{
"id": "contact",
"title": "Contact Us",
"fields": [
{"id": "name", "type": "text", "label": "Name", "required": true},
{"id": "email", "type": "email", "label": "Email", "required": true},
{"id": "message", "type": "textarea", "label": "Message"}
]
}
"""
let formSchema = try JSONFormBuilder.parse(schema)
JSONFormView(schema: formSchema, state: formState)// Enable analytics
FormAnalytics.shared.addProvider(ConsoleAnalyticsProvider())
// Track form
FormContainer(title: "Survey")
.trackAnalytics(formId: "survey-form", totalFields: 10)
// View analytics dashboard
FormAnalyticsDashboard(formId: "survey-form")FormContainer(title: "Quick Form") {
FormSection("Info") {
Field("Name", required: true) {
TextField("", text: $name)
}
FormRow {
Field("First") { TextField("", text: $first) }
Field("Last") { TextField("", text: $last) }
}
}
ConditionalField(when: showOptional) {
Field("Optional") { TextField("", text: $optional) }
}
SubmitButton("Submit", icon: "paperplane")
}// Use built-in theme
FormContainer(theme: .dark) { ... }
// Custom theme
let customTheme = FormTheme(
primaryColor: .blue,
errorColor: .red,
successColor: .green,
labelColor: .primary,
backgroundColor: .clear,
borderColor: .gray.opacity(0.3),
cornerRadius: 12,
spacing: 16
)
FormContainer(theme: customTheme) { ... }SwiftUI Forms Kit is built with accessibility in mind:
// All fields have proper labels
FormTextField("Email", text: $email)
.accessibilityHint("Enter your email address")
// Error announcements
.accessibilityAnnouncement(error)
// VoiceOver support for all interactions
// Dynamic Type support
// Reduce Motion support| Platform | Minimum Version |
|---|---|
| iOS | 16.0+ |
| macOS | 13.0+ |
| tvOS | 16.0+ |
| watchOS | 9.0+ |
π Full Documentation
Contributions are welcome! Please read our Contributing Guide first.
MIT License - see LICENSE for details.
Made with β€οΈ by Muhittin Camdali