The SixLayer Framework supports field-level display hints that describe your data. You create .hints files that describe how to present your data models, and 6Layer automatically reads and uses them.
Key insight: Hints describe the DATA, so they're stored in .hints files that correspond to your data models, not passed in manually.
Field hints are stored in .hints files in a Hints/ subfolder. The name matches your data model:
YourApp/
Models/
User.swift # Your User data model
Hints/ # Hints subfolder (created by you)
User.hints # How to present User data
Product.hints # How to present Product data
Create a file named {YourModelName}.hints in your project:
User.hints:
{
"username": {
"expectedLength": 20,
"displayWidth": "medium",
"maxLength": 50,
"minLength": 3,
"showCharacterCounter": "false"
},
"email": {
"expectedLength": 30,
"displayWidth": "wide",
"maxLength": 255
},
"bio": {
"expectedLength": 500,
"displayWidth": "wide",
"maxLength": 1000,
"showCharacterCounter": "true"
},
"postalCode": {
"expectedLength": 10,
"displayWidth": "narrow",
"maxLength": 10
},
"sizeUnit": {
"displayWidth": "medium",
"expectedLength": 15,
"inputType": "picker",
"options": [
{"value": "story_points", "label": "Story Points"},
{"value": "hours", "label": "Hours"},
{"value": "days", "label": "Days"},
{"value": "weeks", "label": "Weeks"},
{"value": "t_shirt", "label": "T-Shirt Size"}
]
}
}NEW in v5.4.0: You can also include OCR hints and calculation groups in hints files!
NEW in v5.7.1: Value range validation for OCR-extracted numeric fields!
NEW in v5.8.0: Picker options for enum fields with human-readable labels!
NEW in v5.8.0: Automatic DataBinder creation for real-time model updates!
See the Hints File OCR and Calculations Guide for complete documentation.
See the IntelligentFormView Auto-Binding Guide for automatic data binding documentation.
// User.swift
struct User {
let username: String
let email: String
let bio: String?
let postalCode: String
}Create a Hints/ folder in your project and add User.hints:
YourApp/
Models/
User.swift
Hints/
User.hints <- 6Layer reads this automatically
Note: Add the Hints/ folder to your Xcode project and include the .hints files in your target.
6Layer automatically reads the .hints file:
struct CreateUserView: View {
let fields = createUserFields()
var body: some View {
// Pass modelName to tell 6Layer which .hints file to read
platformPresentFormData_L1(
fields: fields,
hints: EnhancedPresentationHints(
dataType: .form,
presentationPreference: .form,
context: .create
),
modelName: "User" // 6Layer reads User.hints automatically!
)
}
}6Layer automatically:
- Reads the
User.hintsfile - Applies display widths to each field
- Uses expected lengths for sizing
- Shows character counters when configured
- Creates a
DataBinderfor real-time model updates (v5.8.0+)
No manual hint passing needed! The hints describe your data model.
📚 Data Binding: For information about automatic DataBinder creation and real-time model updates, see the IntelligentFormView Auto-Binding Guide.
public struct FieldDisplayHints: Sendable {
/// Expected maximum length (for display sizing)
public let expectedLength: Int?
/// Display width: "narrow", "medium", "wide", or numeric value
public let displayWidth: String?
/// Whether to show a character counter
public let showCharacterCounter: Bool
/// Maximum allowed length (for validation)
public let maxLength: Int?
/// Minimum allowed length (for validation)
public let minLength: Int?
/// Expected value range for numeric fields (for OCR validation) (NEW in v5.7.1)
/// When specified, OCR-extracted numeric values outside this range will be filtered out
/// Format: {"min": 5.0, "max": 30.0} in hints files
public let expectedRange: ValueRange?
/// Additional metadata
public let metadata: [String: String]
/// OCR hints for field identification (NEW in v5.4.0)
public let ocrHints: [String]?
/// Calculation groups for computing field values (NEW in v5.4.0)
public let calculationGroups: [CalculationGroup]?
}📚 For complete OCR hints, calculation groups, and value ranges documentation, see:
- Hints File OCR and Calculations Guide - Complete guide to OCR hints, calculations, and value ranges in hints files
NEW in v6.1.0: You can now make hints fully declarative by adding type information. This enables type-only form generation - creating forms without requiring instance data.
Fully declarative hints include type information (fieldType, isOptional, isArray, defaultValue) that allows the framework to generate forms from hints alone, without needing to examine actual data instances using Mirror reflection.
- Type-Only Forms: Generate forms without creating instance data
- Self-Documenting: Hints become complete data schemas
- Better Control: Explicitly define what fields exist and their types
- Code Generation: Use hints as source of truth for documentation/tools
- Performance: Skip Mirror reflection when hints are complete
Add type information to your hints:
{
"username": {
"fieldType": "string", // NEW: Field type
"isOptional": false, // NEW: Whether field can be nil
"isArray": false, // NEW: Whether field is an array
"defaultValue": null, // NEW: Default value (optional)
"expectedLength": 20,
"displayWidth": "medium",
"maxLength": 50
},
"email": {
"fieldType": "string",
"isOptional": true,
"displayWidth": "wide"
},
"age": {
"fieldType": "number",
"isOptional": false,
"expectedRange": {"min": 0, "max": 120},
"displayWidth": "narrow"
},
"isActive": {
"fieldType": "boolean",
"isOptional": false,
"defaultValue": true
},
"tags": {
"fieldType": "string",
"isArray": true,
"displayWidth": "wide"
}
}The fieldType property supports:
"string"- Text fields"number"- Numeric fields (Int, Double, Float)"boolean"- Boolean/toggle fields"date"- Date fields"url"- URL fields"uuid"- UUID fields"document"- Document/file fields"image"- Image fields"custom"- Custom types
A hint is fully declarative when it has both fieldType and isOptional specified:
{
"username": {
"fieldType": "string", // ✅ Has fieldType
"isOptional": false // ✅ Has isOptional
// This hint is fully declarative!
}
}The framework uses a hybrid approach:
- Hints-First: If hints are fully declarative, use them
- Mirror Fallback: If hints are incomplete or missing, use Mirror reflection
- Best of Both: Automatic by default (Mirror), explicit when needed (hints)
Example - Partial Hints (Mirror Fallback):
{
"email": {
"displayWidth": "wide",
"maxLength": 255
// No fieldType/isOptional - Mirror will discover it
}
}With fully declarative hints, you can generate forms without instance data:
// Generate form from type + hints only (no instance needed)
IntelligentFormView.generateForm(
for: User.self, // Type only
initialData: nil, // No instance data
onSubmit: { user in
// Handle created user
},
onCancel: {
// Handle cancel
}
)The framework will:
- Load hints for
User - Verify hints are fully declarative
- Create a blank entity (Core Data or SwiftData) with defaults from hints
- Generate form for the new entity
The hints generator (scripts/generate_hints_from_models.swift) rewrites the top-level __example object on every run so it always reflects the current set of documented keys and patterns (nested field template, sample _sections, sample _defaults, and related options). It is not a hand-maintained fragment inside an otherwise frozen file.
Structurally, __example mirrors what a hints file can contain: for example a template field entry (under a key such as __examplefield) plus illustrative _sections and _defaults. The exact keys evolve with the script; treat the generated block as the source of truth when adding or editing real field entries.
This field serves as self-documentation alongside your real model keys (username, amount, …).
Note: The __example key is ignored during form loading—it is documentation only.
To migrate existing hints to fully declarative:
- Add
fieldType: Determine the type for each field - Add
isOptional: Mark optional fields astrue, required asfalse - Add
isArray(if needed): Mark array/collection fields astrue - Add
defaultValue(optional): Specify default values where appropriate
Example Migration:
Before (display hints only):
{
"username": {
"displayWidth": "medium",
"maxLength": 50
}
}After (fully declarative):
{
"username": {
"fieldType": "string",
"isOptional": false,
"displayWidth": "medium",
"maxLength": 50
}
}Backward Compatibility: Existing hints without type information continue to work - Mirror reflection is used as fallback.
The script scripts/generate_hints_from_models.swift builds or updates {ModelName}.hints from a Swift source file (-model) or a Core Data model (-modeld). Run it with the Swift toolchain, for example:
swift scripts/generate_hints_from_models.swift \
-model Models/User.swift \
-extensionsdir Models \
-outputdir HintsArguments (see -h in the script for the canonical list):
| Flag | Purpose |
|---|---|
-model <path> |
Single .swift file that defines (or extends) the model; exactly one of -model or -modeld is required. |
-modeld <path> |
.xcdatamodel directory or .xcdatamodeld bundle. |
-extensionsdir <path> |
Extra directories to search for extension TypeName files (Swift only); may be repeated. |
-outputdir <path> |
Where to write .hints files (default: Hints under the current working directory). |
When a .hints file already exists, regeneration is designed around two ideas: keep author-edited presentation hints, and keep type/default alignment with the model where the script can infer it.
-
Structural keys (per field) — If a field object is missing any of these, they are filled from the model:
fieldType,isOptional,isArray,isHidden,isEditable. If the file already sets them, they are not overwritten (so you can override generator defaults such as hiding UUIDs). -
defaultValue(Swift models only) — If the parser finds a simple property initializer (= literal) on a stored property, the script writesdefaultValuein hints to match that literal on every run—including when you change the literal in Swift (so hints stay in sync). Supported shapes match the script’s parser (e.g. string, numeric, boolean literals). If the model has no parseable initializer, any existingdefaultValuein the hints file is left unchanged (the script does not delete hints-only defaults). -
defaultValue(Core Data) — Attributes are emitted with structural fields only; the script does not currently map Core Data default strings intodefaultValuein.hints. SetdefaultValuein JSON by hand if you need it. -
Never from the model script — Keys such as
placeholder,expectedLength,displayWidth, picker options, etc. are only what you put in JSON (or copy from__example). The generator does not infer UX copy or presentation from Swift beyond the structural list above and Swift literaldefaultValue. -
_sections— If the file already defines_sections, they are preserved. If there are no sections, the script may add a minimal default section listing known fields. -
_defaults— If you already have presentation defaults under_defaults, they are preserved. If the file has no color-related defaults, the script may inject a small example block so the feature is discoverable (you can edit or remove it). -
__example— Always replaced with the script’s current full template so documentation stays up to date. -
Field order — Existing top-level field key order is preserved when possible; new properties discovered from the model are appended.
New files: If no .hints file exists yet, the script creates one with structural entries for each model field, Swift-sourced defaultValue when applicable, optional default _sections / _defaults as above, and __example.
The Swift side uses a regex-based extractor (not SwiftSyntax). Behavior when the model does not match what the script understands:
| Situation | What the parser does | Effect on .hints |
|---|---|---|
Line does not match the property pattern (e.g. complex generic type with <…>, wrappers/attributes that break the line, var/let forms outside the supported grammar) |
Property is skipped—no FieldInfo for that name from this file. |
That field is not updated or added by this parse pass. Any existing JSON entry for the same key is left as-is (stale hints are possible if you rename/remove a property and the line no longer matches). |
Computed property ({ immediately after the type) |
Still listed with structural hints; isEditable follows ID/computed rules. |
No defaultValue from Swift (no stored initializer). |
= present but literal not understood (e.g. = UUID(), = .red, = 1_000, hex 0xFF, expressions, multi-line values) |
parseDefaultValue returns no value for that property. |
defaultValue in hints is not overwritten—whatever you already had in JSON stays (including omission). The script does not write the raw expression text into hints. |
fieldType is date, url, uuid, document, image, or custom |
Initializers are not parsed into JSON defaults (only string / number / boolean literals are). |
Same as row above: no model-driven defaultValue update from = …. |
| Number | Only decimal integer or floating text that Int/Double can parse. |
Unparseable → no model defaultValue sync. |
| Boolean | Only the tokens true and false. |
Anything else → no model defaultValue sync. |
| String | Quoted "…" content is unescaped into the value; other non-empty text is taken as a single token (limited). |
Complex string literals or interpolation are not supported. |
Practical takeaway: If the generator ignores a default you care about, set defaultValue (or placeholder) explicitly in the .hints file—that remains the source of truth whenever the parser cannot map Swift to JSON.
NEW in v5.8.0: You can now specify enum fields as pickers with human-readable labels!
Use pickers when a field represents an enum or a fixed set of values. This provides better UX than requiring users to type raw enum values.
Add inputType: "picker" and an options array to your field definition:
{
"sizeUnit": {
"displayWidth": "medium",
"expectedLength": 15,
"inputType": "picker",
"options": [
{"value": "story_points", "label": "Story Points"},
{"value": "hours", "label": "Hours"},
{"value": "days", "label": "Days"},
{"value": "weeks", "label": "Weeks"},
{"value": "t_shirt", "label": "T-Shirt Size"}
]
}
}- Display: The picker shows human-readable
labelvalues (e.g., "Story Points", "Hours") - Storage: The model stores the raw
value(e.g., "story_points", "hours") - Platform Support: Works on both macOS (menu style) and iOS (menu style)
- Backward Compatible: Fields without
inputTypecontinue to render as TextFields
NEW: All DynamicFormField components now automatically understand and respect hints:
DynamicTextField: ChecksinputType == "picker"and renders a picker whenpickerOptionsare availableDynamicSelectField: PreferspickerOptionsfrom hints (with labels) overfield.options(simple strings)DynamicEnumField: PreferspickerOptionsfrom hints (with labels) overfield.options(simple strings)
Components automatically:
- Check
displayHints.inputTypeanddisplayHints.pickerOptionsfirst - Fall back to
field.optionsif hints aren't available - Use labeled options (
PickerOption.labelfor display,PickerOption.valuefor storage) when available
This means you can configure pickers entirely through hints files, and components will automatically use them!
struct Task {
let sizeUnit: String // Will use picker if hints specify inputType: "picker"
let name: String // Will use TextField (default)
}With the hints file above, sizeUnit will render as a picker with labels, while name remains a text field.
Framework-owned field layouts honor FieldDisplayHints for preferred width, packing, and alignment. Ignoring these hints in a framework-owned layout is a bug.
Multi-field (shared packer + aligner):
| Surface | Path |
|---|---|
| DynamicForm | DynamicFormSectionView → PackedDynamicFormFieldsLayout |
| IntelligentFormView | vertical / horizontal / grid / adaptive → PackedIntelligentFormFieldsLayout |
GenericFormView / ModalFormView / platformPresentModalForm_L1 |
PackedGenericFormFieldsLayout |
platformPresentFormData_L1 |
AsyncFormView → DynamicForm |
Single-field chrome (width via applyFieldHints):
platformFormField(label:displayHints:content:)iOSTouchFormField(..., displayHints:)macOSDesktopFormField(..., displayHints:)CustomFieldView/ Dynamic*Field preferred-width defaults
Read-only detail rows (IntelligentDetailView) are not form packing surfaces.
- Numeric
displayWidth(e.g."250") → exact points - Named band
narrow/medium/wide→ platform band table (below) expectedLength→ about N characters × control font metrics (FieldDisplayCharacterMetricsviaDynamicFontResolverbody style, Dynamic Type aware) + padding- Otherwise → flexible within the window (still capped by container; not free to overflow the screen)
Always: effective = min(preferred, availableWidth) when a preferred width is set.
displayWidth omitted is not medium — it means no band preference (fall through to expectedLength or flexible).
Bands are semantic. Point values differ by platform:
| Band | iOS / touch | macOS / pointer | Typical use |
|---|---|---|---|
narrow |
120 | 150 | postal code, extension |
medium |
180 | 200 | username, city |
wide |
320 | 400 | email, address |
Other platforms currently follow the iOS (compact) table. Document any future platform differences here.
{
"customField": {
"displayWidth": "250"
}
}Numeric values are still capped to available container width.
| Key | Role |
|---|---|
expectedLength |
Layout — size the field for about N characters |
maxLength |
Validation — reject input beyond N (counters / rules) |
displayWidth |
Layout — preferred horizontal field claim |
Do not invent a parallel layout maxWidth hint.
Hints apply to the field’s layout claim (how much horizontal space the field takes). The interactive control lives inside that slot: text-like controls fill the slot (FieldLayoutControlSizing.fillClaim); checkboxes/toggles stay content-sized inside the claim (intrinsicWithinClaim) and do not stretch to invent a wide hit target.
Preferred width claims are capped with measured container availableWidth when packing (and optionally via applyFieldHints(..., availableWidth:)).
PresentationHints.fieldHints[fieldId] wins over the field’s own displayHints / metadata. Use presentation-level hints when constructing ModalFormView / GenericFormView without putting width on each field.
When the framework lays out a list of fields:
- Order: DynamicForm packs section field order. IntelligentFormView packs the effective author order after its priority / order-rules pass (
orderFieldsByPriority/orderRulesProvider) — assigning priorities is how authors express order there, not raw Mirror/file order. - Width-aware rows; wrap when the next field does not fit
- Keep contiguous same-type runs together — never orphan
check, check, check, noteinto[check][check]/[check][note] - Isolate tall / multi-line and wide-flex fields on their own row
- Cap items per row (~3–4); consistent spacing; section boundaries win
- Do not force a balanced
N×Mgrid for neatness when widths/runs say otherwise - Alignment: packed rows use
FieldLayoutPackedSection.plan(FieldLayoutAligner.columnMaxWidths+packedFormControlLeadingInset). Label-above chrome (current) uses inset0; label-leading chrome usesmax(labelWidths) + spacingviasharedControlLeadingInset.
// User.swift
struct User: Identifiable {
let id: UUID
let username: String
let email: String
let bio: String?
let postalCode: String
}User.hints:
{
"username": {
"expectedLength": 20,
"displayWidth": "medium",
"maxLength": 50,
"minLength": 3
},
"email": {
"displayWidth": "wide"
},
"bio": {
"displayWidth": "wide",
"showCharacterCounter": "true"
},
"postalCode": {
"displayWidth": "narrow"
}
}struct CreateUserView: View {
var body: some View {
platformPresentFormData_L1(
fields: createUserFields(),
hints: EnhancedPresentationHints(
dataType: .form,
presentationPreference: .form,
context: .create
),
modelName: "User" // 6Layer reads User.hints automatically!
)
}
}
func createUserFields() -> [DynamicFormField] {
[
DynamicFormField(
id: "username",
contentType: .text,
label: "Username",
isRequired: true
),
DynamicFormField(
id: "email",
contentType: .email,
label: "Email",
isRequired: true
),
DynamicFormField(
id: "bio",
contentType: .textarea,
label: "Biography"
),
DynamicFormField(
id: "postalCode",
textContentType: .postalCode,
label: "Postal Code"
)
]
}That's it! 6Layer automatically reads User.hints and applies the display properties.
The framework automatically applies field hints when rendering forms. Simply include hints in your PresentationHints and the views will respect the display width and other properties.
NEW: DynamicFormField components automatically understand and use hints:
// Create a field - no need to specify options manually
let field = DynamicFormField(
id: "sizeUnit",
contentType: .text, // Can be .text, .select, or .enum
label: "Size Unit"
)
// If User.hints contains:
// {
// "sizeUnit": {
// "inputType": "picker",
// "options": [{"value": "story_points", "label": "Story Points"}, ...]
// }
// }
// Then DynamicTextField will automatically render a picker!Component Behavior:
DynamicTextField: Automatically renders picker wheninputType == "picker"in hintsDynamicSelectField: UsespickerOptionsfrom hints (preferred) orfield.options(fallback)DynamicEnumField: UsespickerOptionsfrom hints (preferred) orfield.options(fallback)
Hints Priority: Components prefer hints over direct field configuration:
displayHints.pickerOptions(from hints file) - Preferred (has labels)field.options(from code) - Fallback (simple strings)
You can also provide picker options via metadata (useful for runtime configuration):
let field = DynamicFormField(
id: "status",
contentType: .select,
label: "Status",
metadata: [
"inputType": "picker",
"pickerOptions": """
[
{"value": "draft", "label": "Draft"},
{"value": "published", "label": "Published"},
{"value": "archived", "label": "Archived"}
]
"""
]
)The displayHints property automatically parses JSON strings from metadata to create PickerOption arrays.
- Configuration-Driven: Hints stored in files, separate from code
- Type-Safe: Strongly-typed FieldDisplayHints structure
- Cached: Registry caches hints for performance
- File-Based: Similar to CoreData models, hints are stored in JSON files
- Flexible: Support for both file-based and runtime configuration
You can control the display order of fields in IntelligentFormView.
Install a provider once (e.g., at app launch):
IntelligentFormView.orderRulesProvider = { analysis in
let names = Set(analysis.fields.map { $0.name })
let isTask = ["title","status","priority","sizeUnit","estimatedHours","notes"].allSatisfy { names.contains($0) }
if isTask {
let base = FieldOrderRules(
explicitOrder: ["title","status","priority","sizeUnit","estimatedHours","notes"]
)
let compact = FieldOrderRules(explicitOrder: ["title","priority","status"])
return FieldOrderRules(
explicitOrder: base.explicitOrder,
perFieldWeights: base.perFieldWeights,
groups: base.groups,
traitOverrides: [.compact: compact]
)
}
return nil // fallback to defaults (title/name first)
}Rules are applied trait-aware (phones -> .compact, others -> .regular). When no provider returns rules, 6Layer defaults to a sensible order that prioritizes common primary fields like title or name first.
public struct FieldGroup: Equatable, Sendable {
public let id: String
public let title: String?
public let fields: [String]
}
public enum FieldTrait: Hashable, Sendable { case compact, regular }
public struct FieldOrderRules: Equatable, Sendable {
public let explicitOrder: [String]? // Highest precedence
public let perFieldWeights: [String: Int] // Higher weight -> earlier
public let groups: [FieldGroup] // Declaration order respected
public let traitOverrides: [FieldTrait: FieldOrderRules]
}Resolver behavior:
- Sort by explicitOrder when provided; unknown keys are ignored.
- Then append remaining fields by weight (desc), then by name for deterministic tie-break.
- Groups render in declaration order; order within each group follows the same rules.
- Trait overrides replace the base rules for that trait.
Validation helper:
let (sorted, warnings) = IntelligentFormView.inspectEffectiveOrder(analysis: analysis)
// warnings contains any unknown keys detected in explicitOrder/weights/groupsEnhancedPresentationHints includes an optional fieldOrderRules to carry deterministic ordering through hints if you prefer to keep ordering near your hint definitions:
let hints = EnhancedPresentationHints(
dataType: .form,
fieldOrderRules: FieldOrderRules(
explicitOrder: ["title","status","priority"]
)
)If both hints and the runtime provider are present, your app-level provider can decide priority by merging or preferring one.
Layout hints allow you to define how groups of fields should be displayed together and what layout style to use for each group. This extends the field-level hints system to include structural organization.
Key principle: Layout hints describe data relationships - which fields belong together and in what order. They're hints, not commandments - the framework adapts layouts responsively based on available space and platform capabilities.
Add a _sections array to your .hints file to define field groupings and layout styles:
User.hints:
{
"username": {
"displayWidth": "medium",
"expectedLength": 20
},
"email": {
"displayWidth": "wide"
},
"bio": {
"displayWidth": "wide",
"showCharacterCounter": true
},
"postalCode": {
"displayWidth": "narrow"
},
"_sections": [
{
"id": "basic-info",
"title": "Basic Information",
"description": "Enter your account details",
"fields": ["username", "email"],
"layoutStyle": "vertical"
},
{
"id": "personal-info",
"title": "Personal Details",
"fields": ["bio", "postalCode"],
"layoutStyle": "horizontal"
}
]
}Each section in _sections supports:
id(required): Unique identifier for the sectiontitle(required): Section title (used for accessibility)description(optional): Section description textfields(optional): Array of field IDs that belong to this section, in display orderlayoutStyle(optional): Layout strategy for fields in this section
The layoutStyle property supports the following values (all are hints - the framework adapts):
vertical(default): Fields stacked verticallyhorizontal: Fields displayed side-by-side (2 columns)grid: Adaptive grid layout based on field countadaptive: Framework chooses layout based on field count (vertical for ≤4, horizontal for ≤8, grid for >8)standard,compact,spacious: Vertical layouts with different spacing
- Explicit LayoutSpec (highest priority): If you pass a
LayoutSpectoplatformPresentFormData_L1, it overrides hints - Hints file
_sections: Sections defined in.hintsfile - Framework defaults (lowest priority): Single default section with all fields
User.hints:
{
"username": {
"displayWidth": "medium",
"expectedLength": 20
},
"email": {
"displayWidth": "wide"
},
"bio": {
"displayWidth": "wide",
"showCharacterCounter": true
},
"phone": {
"displayWidth": "medium"
},
"address": {
"displayWidth": "wide"
},
"postalCode": {
"displayWidth": "narrow"
},
"_sections": [
{
"id": "account",
"title": "Account Information",
"description": "Your login credentials",
"fields": ["username", "email"],
"layoutStyle": "vertical"
},
{
"id": "contact",
"title": "Contact Information",
"fields": ["phone", "address", "postalCode"],
"layoutStyle": "horizontal"
},
{
"id": "profile",
"title": "Profile",
"fields": ["bio"],
"layoutStyle": "vertical"
}
]
}Usage in Swift:
let fields = [
DynamicFormField(id: "username", contentType: .text, label: "Username"),
DynamicFormField(id: "email", contentType: .email, label: "Email"),
DynamicFormField(id: "phone", contentType: .telephoneNumber, label: "Phone"),
DynamicFormField(id: "address", contentType: .text, label: "Address"),
DynamicFormField(id: "postalCode", textContentType: .postalCode, label: "Postal Code"),
DynamicFormField(id: "bio", contentType: .textarea, label: "Biography")
]
platformPresentFormData_L1(
fields: fields,
hints: EnhancedPresentationHints(
dataType: .form,
context: .create
),
modelName: "User" // Loads User.hints with _sections automatically!
)For special cases where you need to override hints programmatically:
let customLayout = LayoutSpec(sections: [
DynamicFormSection(
id: "custom-section",
title: "Custom Layout",
fields: [fields[0], fields[1]],
layoutStyle: .grid
)
])
platformPresentFormData_L1(
fields: fields,
hints: EnhancedPresentationHints(...),
modelName: "User",
layoutSpec: customLayout // Overrides hints file sections
)If a section references a field ID that doesn't exist in your form fields:
- A warning is logged to the console
- The missing field is ignored
- The section is created with the remaining valid fields
This provides graceful degradation - your hints file can reference fields that aren't always present.
Fields within a section are displayed in the order specified in the fields array in your hints file. This gives you full control over field ordering within each section.
- Data-Driven Layout: Layout structure defined with your data, not scattered in code
- DRY: Define layout once in hints, use everywhere
- Responsive: Framework adapts layouts based on available space
- Accessible: Section titles used for accessibility identifiers
- Flexible: Can override programmatically with
LayoutSpecwhen needed - Backward Compatible: Existing hints files without
_sectionscontinue to work