A SwiftUI component for building forms from JSON Schema. This library provides a convenient way to generate dynamic forms based on a JSON Schema, with built-in validation and customization options.
- Generate forms automatically from JSON Schema
- Field validation based on schema constraints
- Custom validation support
- UI customization via uiSchema
- Support for all standard JSON Schema types:
- String with various formats
- Number/Integer with range validation
- Boolean
- Object (nested forms)
- Array
- Error display and handling
- Form submission and data change events
Add the package to your Package.swift
file:
dependencies: [
.package(url: "https://github.com/yourusername/JSONSchemaForm.git", .upToNextMajor(from: "1.0.0"))
],
targets: [
.target(
name: "YourTarget",
dependencies: ["JSONSchemaForm"]),
]
Or add it through Xcode:
- Go to File > Swift Packages > Add Package Dependency
- Enter the repository URL:
https://github.com/yourusername/JSONSchemaForm.git
- Choose the version you want
import SwiftUI
import JSONSchema
import JSONSchemaForm
struct ContentView: View {
// Define your JSON Schema
let schema: JSONSchema = .object(
properties: [
"name": .string(description: "Full name"),
"email": .string(format: "email", description: "Email address"),
"age": .integer(minimum: 18, description: "Age (must be 18 or older)"),
"agreeToTerms": .boolean(description: "I agree to the terms and conditions")
],
required: ["name", "email", "agreeToTerms"]
)
// Initial form data (optional)
@State private var formData: [String: Any]? = nil
var body: some View {
VStack {
// Render the form
JSONSchemaForm(
schema: schema,
formData: formData,
onChange: { newData in
// Handle data changes
if let data = newData as? [String: Any] {
self.formData = data
}
},
onSubmit: { data in
// Handle form submission
if let formData = data as? [String: Any] {
print("Form submitted with data: \(formData)")
}
},
onError: { errors in
// Handle validation errors
print("Validation errors: \(errors)")
}
)
}
.padding()
}
}
Use a uiSchema
to customize the appearance and behavior of form fields:
let uiSchema: [String: Any] = [
"name": [
"ui:autofocus": true,
"ui:placeholder": "Enter your full name"
],
"email": [
"ui:placeholder": "[email protected]"
],
"age": [
"ui:widget": "updown" // Use an up/down control instead of a text field
],
"agreeToTerms": [
"ui:widget": "radio" // Use radio buttons instead of a checkbox
]
]
// Then in your view:
JSONSchemaForm(
schema: schema,
uiSchema: uiSchema,
formData: formData,
// ... other props
)
You can add custom validation logic that goes beyond JSON Schema validation:
let customValidate: (Any?, inout [String: Any]) -> Void = { formData, errorSchema in
// Make sure we have form data as a dictionary
guard let data = formData as? [String: Any] else { return }
// Custom validation for name field
if let name = data["name"] as? String {
if name.count < 5 {
if errorSchema["name"] == nil {
errorSchema["name"] = ["__errors": ["Name must be at least 5 characters"]]
} else if var nameErrors = errorSchema["name"] as? [String: Any] {
if nameErrors["__errors"] == nil {
nameErrors["__errors"] = ["Name must be at least 5 characters"]
} else if var errors = nameErrors["__errors"] as? [String] {
errors.append("Name must be at least 5 characters")
nameErrors["__errors"] = errors
}
errorSchema["name"] = nameErrors
}
}
}
// Add more custom validation as needed
}
// Then in your view:
JSONSchemaForm(
schema: schema,
uiSchema: uiSchema,
formData: formData,
customValidate: customValidate,
// ... other props
)
Create more complex forms with nested objects, arrays, and conditional logic:
let advancedSchema: JSONSchema = .object(
properties: [
"personalInfo": .object(
properties: [
"name": .string(),
"email": .string(format: "email")
],
required: ["name", "email"]
),
"address": .object(
properties: [
"street": .string(),
"city": .string(),
"state": .enum(values: [
.string("CA"),
.string("NY"),
.string("TX")
]),
"zipCode": .string(pattern: "^\\d{5}$")
],
required: ["street", "city", "state", "zipCode"]
),
"phoneNumbers": .array(
items: .object(
properties: [
"type": .enum(values: [.string("home"), .string("work"), .string("mobile")]),
"number": .string(pattern: "^\\d{3}-\\d{3}-\\d{4}$")
],
required: ["type", "number"]
),
minItems: 1
)
],
required: ["personalInfo"]
)
The JSONSchemaForm
component accepts the following properties:
Property | Type | Description |
---|---|---|
schema |
JSONSchema |
The JSON Schema that defines the form structure (required) |
uiSchema |
[String: Any]? |
Customization options for form appearance and behavior |
formData |
Any? |
Initial data for the form |
onChange |
((Any?) -> Void)? |
Called when form data changes |
onSubmit |
((Any?) -> Void)? |
Called when form is submitted successfully |
onError |
(([ValidationError]) -> Void)? |
Called when validation errors occur on submit |
formContext |
[String: Any]? |
Context data passed to all fields |
liveValidate |
Bool |
Whether to validate as the user types (default: false) |
showErrorList |
Bool |
Whether to show error summary at the top (default: true) |
transformErrors |
(([ValidationError]) -> [ValidationError])? |
Function to transform validation errors |
disabled |
Bool |
Whether the entire form is disabled (default: false) |
readonly |
Bool |
Whether the entire form is read-only (default: false) |
customValidate |
((Any?, inout [String: Any]) -> Void)? |
Custom validation function |
idPrefix |
String |
Prefix for form field IDs (default: "root") |
idSeparator |
String |
Separator for nested field IDs (default: "_") |
The uiSchema
object lets you customize how the form is rendered:
ui:readonly
: Make all fields read-onlyui:disabled
: Disable all fieldsui:classNames
: Add custom CSS class names to the form
For each field in your schema, you can specify:
ui:widget
: Override the default widget (e.g., "textarea", "select", "radio", "password")ui:placeholder
: Add placeholder text to input fieldsui:autofocus
: Automatically focus on this field when the form loadsui:help
: Help text to display below the fieldui:title
: Custom title for the fieldui:description
: Custom description for the fieldui:options
: Additional widget-specific options
This project is available under the MIT License. See the LICENSE file for more info.