@sonata-innovations/fiber-types 2.2.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,875 @@
1
+ ---
2
+ title: Flow JSON Schema Reference
3
+ applies-to:
4
+ - "@sonata-innovations/fiber-types@^2.2"
5
+ read-when: "Exhaustive per-property reference for Flow JSON: every component type, property, condition, validation rule, calculation, and config field. For a compact overview use flow-quick-reference.md."
6
+ ---
7
+
8
+ <!-- Generated from the Fiber repo's docs/ tree by project/scripts/sync-package-docs.mjs. Do not edit here. -->
9
+ # Fiber JSON Schema
10
+
11
+ > Canonical source: [`flow-schema.json`](flow-schema.json)
12
+ >
13
+ > **TypeScript shape**: as of `@sonata-innovations/fiber-types` v2, `Component` is a discriminated union keyed on `type` — `component.properties` narrows to the matching `Component*Properties` shape after a `type` check. The Flow JSON described here is unchanged.
14
+
15
+ The Flow JSON is the interchange format between FBT (the builder UI) and FBRE (the render engine). FBT authors it; FBRE consumes it and renders the form.
16
+
17
+ ---
18
+
19
+ ## Flow (root)
20
+
21
+ | Field | Type | Required | Description |
22
+ | ---------- | --------------------------------------- | -------- | ------------------------------ |
23
+ | `uuid` | `string` | Yes | Unique identifier for the flow |
24
+ | `metadata` | [FlowMetadata](#flowmetadata) | Yes | Descriptive metadata |
25
+ | `config` | [FlowConfiguration](#flowconfiguration) | No | Runtime configuration |
26
+ | `screens` | [FlowScreen](#flowscreen)[] | Yes | Ordered list of screens |
27
+ | `calculations` | [FlowCalculation](#flowcalculation)[] | No | Top-level calculations |
28
+
29
+ ---
30
+
31
+ ## FlowMetadata
32
+
33
+ Descriptive metadata for the flow. Accepts additional string properties beyond the ones listed.
34
+
35
+ | Field | Type | Required | Description |
36
+ | ------------- | -------- | -------- | ----------------------- |
37
+ | `name` | `string` | No | Name of the flow |
38
+ | `description` | `string` | No | Description of the flow |
39
+
40
+ ---
41
+
42
+ ## FlowConfiguration
43
+
44
+ Runtime configuration for the flow, organized into semantic groups.
45
+
46
+ | Field | Type | Required | Description |
47
+ | ------------ | ------------------ | -------- | ------------------------------------ |
48
+ | `mode` | `FlowModeType` | No | Form presentation mode. See [Conversational Mode](#conversational-mode) |
49
+ | `theme` | `ThemeConfig` | No | Visual theme settings |
50
+ | `navigation` | `NavigationConfig` | No | Screen navigation settings |
51
+ | `controls` | `ControlsConfig` | No | Navigation controls settings |
52
+ | `summary` | `boolean` | No | Show a summary screen before completion |
53
+ | `confirmation` | `ConfirmationConfig` | No | Terminal thank-you screen shown after submission |
54
+
55
+ ### ThemeConfig
56
+
57
+ The theme has two layers: `colorScheme` + `style` pick built-in presets (the seed palette and the shape), and the palette knobs override individual `--fbre-*` tokens on top. Any subset of knobs may be set; unset knobs fall through to the preset. Consumers needing finer control can still override the raw `--fbre-*` CSS custom properties directly.
58
+
59
+ | Field | Type | Required | Description |
60
+ | ------------ | --------------- | -------- | --------------------------------------------------------------------------- |
61
+ | `color` | `string` | No | Accent / primary color (`--fbre-theme-color`) |
62
+ | `colorScheme`| `"light" \| "dark"` | No | Built-in palette preset that seeds the token layer. Default `"light"`. Replaces the former `darkMode` boolean |
63
+ | `style` | `FlowStyleType` | No | Visual style for form elements. See [Style Types](#style-types) |
64
+ | `background` | `string` | No | Page/form ground (`--fbre-bg`) |
65
+ | `surface` | `string` | No | Raised surface: input fills, cards, popups (`--fbre-surface`) |
66
+ | `text` | `string` | No | Primary text color (`--fbre-text`); derives secondary/placeholder/label |
67
+ | `border` | `string` | No | Border/rule color (`--fbre-border`); derives hover/light/subtle |
68
+ | `radius` | `string` | No | Corner radius, any CSS length (`--fbre-radius`), e.g. `"3px"` |
69
+ | `fontFamily` | `string \| FontFamilyConfig` | No | Font family (`--fbre-font`). See [FontFamilyConfig](#fontfamilyconfig) |
70
+ | `error` | `string` | No | Error state color (`--fbre-error`) |
71
+ | `success` | `string` | No | Success state color (`--fbre-success`) |
72
+ | `warning` | `string` | No | Warning state color (`--fbre-warning`) |
73
+
74
+ #### FontFamilyConfig
75
+
76
+ A plain string is a CSS stack and nothing more: the form renders in that family only if the host page already loaded it, and falls back to `system-ui` otherwise — silently, and to something that looks approximately fine. Passing an object instead gives the renderer the sources, and FBRE registers the faces in the owning document itself.
77
+
78
+ That matters most where the host cannot patch around it. FBRE is designed to mount inside a shadow root, and `@font-face` rules declared inside a shadow root's stylesheet are never registered — faces resolve at document level only.
79
+
80
+ | Field | Type | Required | Description |
81
+ | -------- | ------------------ | -------- | ------------------------------------------------------------------ |
82
+ | `family` | `string` | Yes | CSS family name, used for both the `@font-face` and the token value |
83
+ | `src` | `FontSource[]` | No | Shorthand for a single regular face. Merged with `faces` |
84
+ | `faces` | `FontFaceConfig[]` | No | Additional faces — a second weight, an italic |
85
+ | `stack` | `string` | No | Full stack written to `--fbre-font`. Defaults to the family plus a system fallback |
86
+
87
+ `FontSource` is `{ url, format? }`; `FontFaceConfig` is `{ src, weight?, style?, display?, unicodeRange? }`.
88
+
89
+ ```json
90
+ {
91
+ "fontFamily": {
92
+ "family": "Brand Sans",
93
+ "src": [{ "url": "https://cdn.example.com/brand.woff2", "format": "woff2" }],
94
+ "faces": [
95
+ { "src": [{ "url": "https://cdn.example.com/brand-bold.woff2", "format": "woff2" }], "weight": "700" }
96
+ ]
97
+ }
98
+ }
99
+ ```
100
+
101
+ See [FBRE Theming Guide → Loading a brand font](@sonata-innovations/fiber-fbre/docs/features/fbre-theming.md#loading-a-brand-font).
102
+
103
+ #### Style Types
104
+
105
+ **Standard mode styles** (6):
106
+
107
+ | Value | Description |
108
+ | --- | --- |
109
+ | `"clean"` | Bottom-border inputs with uppercase labels (default) |
110
+ | `"outlined"` | Full-border inputs with normal-case labels |
111
+ | `"refined-clean"` | Animated underline focus with left-accent groups |
112
+ | `"airy-clean"` | Spacious layout with tinted focus and pill buttons |
113
+ | `"soft-outlined"` | Full-border 8px radius with shadow-ring focus |
114
+ | `"defined-outlined"` | Filled-background inputs with top-accent groups |
115
+
116
+ **Conversational mode styles** (4):
117
+
118
+ | Value | Description |
119
+ | --- | --- |
120
+ | `"centered-minimal"` | Thin underline inputs, 1px bordered option cards (6px radius), uppercase 12px labels, theme-tinted hover/selected |
121
+ | `"stacked-cards"` | Filled background cards with left accent bar, keyboard shortcut badges (A, B, C, D) on options |
122
+ | `"soft-float"` | Pill-shaped options (24px radius) with shadow lift on hover, rounded inputs and buttons |
123
+ | `"bold-statement"` | 2px borders, 700-weight 24px headers, inverted selection (dark fill + white text), filled input backgrounds |
124
+
125
+ Each style has a default stepper visual (see `stepperStyle`). When switching form mode in FBT, the style auto-switches to the first style of the target mode.
126
+
127
+ ### NavigationConfig
128
+
129
+ | Field | Type | Required | Description |
130
+ | ------------------------ | ---------------------- | -------- | --------------------------------------------------------------------------- |
131
+ | `transition` | `ScreenTransitionType` | No | Screen transition animation type. See [Screen Transitions](#screen-transitions) |
132
+ | `allowInvalidTransition` | `boolean` | No | Allow navigating forward even when the screen has validation errors |
133
+
134
+ ### ControlsConfig
135
+
136
+ | Field | Type | Required | Description |
137
+ | ------------ | -------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
138
+ | `show` | `boolean` | No | Show built-in next/back navigation buttons. Default `true` |
139
+ | `layout` | `"default"` \| `"centered"` \| `"inline-full"` \| `"stacked"` | No | Layout for the navigation controls. `"default"` = side-by-side grid (back-left / stepper-center / next-right); single-button rows collapse to full-width. `"centered"` = stepper row above, buttons centered as a group. `"inline-full"` = stepper row above, buttons side-by-side at 50% each (full-width when solo). `"stacked"` = stepper, Back, Next, all stacked full-width |
140
+ | `showStepper`| `boolean` | No | Show the step indicator dots in the controls bar. Default `true` |
141
+ | `stepperStyle`| `"default"` \| `"dots"` \| `"pill"` \| `"glow"` \| `"bar"` \| `"text"` | No | Style of the step indicator. `"default"` = use the form style's default stepper. `"dots"` = standard circles, scale on active. `"pill"` = active dot stretches to pill shape. `"glow"` = active dot gets a glow ring. `"bar"` = track + counter. `"text"` = "Step X of Y" above screen content. Default `"default"` |
142
+
143
+ ### ConfirmationConfig
144
+
145
+ A terminal "thank you" screen shown after the flow is submitted (once `onFlowComplete` resolves). It is presentation-only — not a data-collection `Screen` — so it lives on the config. In local and remote modes the screen renders only when `show` is not `false` **and** `title` or `body` has content; server-driven mode falls back to a generic "Thank you" when nothing is configured, and renders nothing on an explicit `show: false` (see [Per-mode behavior](@sonata-innovations/fiber-fbre/docs/features/confirmation-screen.md#per-mode-behavior)). When shown, it replaces the final screen and the navigation controls/stepper are hidden.
146
+
147
+ `title` and `body` support the same `${...}` reference markup as display components — references resolve against collected field values, calculations, and external `context` values (by name). A parent application can also override the configured message at runtime by returning (or resolving with) a `{ title?, body? }` object from `onFlowComplete` — useful for post-submit data such as a server-generated reference number.
148
+
149
+ | Field | Type | Required | Description |
150
+ | ------- | --------- | -------- | ------------------------------------------------------------------ |
151
+ | `show` | `boolean` | No | Explicit off-switch. Content presence is the positive gate |
152
+ | `title` | `string` | No | Heading text. Supports `${...}` references and formatting |
153
+ | `body` | `string` | No | Body text. Supports `${...}` references and formatting |
154
+
155
+ ---
156
+
157
+ ## Conversational Mode
158
+
159
+ Set `config.mode` to `"conversational"` to transform FBRE into a one-question-per-screen experience optimized for completion rates.
160
+
161
+ **`FlowModeType`**: `"standard"` | `"conversational"` (default: `"standard"`)
162
+
163
+ ### Behaviors
164
+
165
+ | Behavior | Description |
166
+ | --- | --- |
167
+ | **Vertical centering** | Content is vertically and horizontally centered within the viewport |
168
+ | **Auto-advance** | Single-select components (`radio`, `yesNo`, `cardSelect`, `dropDown`) advance to the next screen ~500ms after selection. Multi-select (`checkbox`, `dropDownMulti`) does NOT auto-advance |
169
+ | **Enter-to-advance** | Pressing Enter on `inputText` / `inputNumber` advances to the next screen. `inputTextArea` is excluded (Enter inserts newlines) |
170
+ | **Animated entry** | Components fade + scale in with staggered delays on screen transitions. Respects `prefers-reduced-motion` |
171
+ | **Larger tap targets** | Yes/No buttons, option items, card-select cards, and input fields are enlarged for easier tapping |
172
+
173
+ ### Conversational styles
174
+
175
+ Conversational mode has 4 dedicated styles (separate from the 6 standard styles):
176
+
177
+ | Style | Personality |
178
+ | --- | --- |
179
+ | `centered-minimal` | Thin underline inputs, bordered option cards, uppercase labels, theme-tinted hover/selected |
180
+ | `stacked-cards` | Filled background cards with left accent bar, keyboard shortcut badges (A, B, C, D) on options |
181
+ | `soft-float` | Pill-shaped options with shadow lift on hover, rounded inputs and buttons |
182
+ | `bold-statement` | Heavy borders, bold typography, inverted selection (dark fill + white text) |
183
+
184
+ When switching to conversational mode in FBT, the style auto-switches to `"centered-minimal"` and the transition to `"scaleFade"`.
185
+
186
+ ### Guards
187
+
188
+ - Auto-advance does **not** fire on the last screen
189
+ - Auto-advance does **not** fire if the screen fails validation
190
+ - Auto-advance respects condition-hidden screens (skips them)
191
+ - Auto-advance does **not** fire during an active transition
192
+ - Enter-to-advance validates the screen before advancing
193
+
194
+ ---
195
+
196
+ ## FlowScreen
197
+
198
+ A single screen (page) in the flow.
199
+
200
+ | Field | Type | Required | Description |
201
+ | ----------------- | ------------------------------------------- | -------- | ---------------------------------------------------------------------------- |
202
+ | `uuid` | `string` | Yes | Unique identifier for the screen |
203
+ | `label` | `string` | No | Display label shown in navigation |
204
+ | `components` | [Component](#component)[] | Yes | Components on this screen |
205
+ | `conditions` | [FlowConditionConfig](#flowconditionconfig) | No | Condition for showing/hiding the screen |
206
+ | `nextButtonLabel` | `string` | No | Custom label for the Next/Done navigation button. Overrides the default text |
207
+ | `backButtonLabel` | `string` | No | Custom label for the Back navigation button. Overrides the default text |
208
+ | `valid` | `boolean` | No | _Runtime only._ Do not set in authored JSON |
209
+
210
+ ---
211
+
212
+ ## Component
213
+
214
+ A single form component. Components are recursive — `group` components contain child components.
215
+
216
+ | Field | Type | Required | Description |
217
+ | ----------------- | ------------------------------------------- | -------- | -------------------------------------------------------------- |
218
+ | `uuid` | `string` | Yes | Unique identifier for the component |
219
+ | `type` | `string` (enum — see [Component Types](#component-types)) | Yes | Component type key. In TypeScript, narrowing on this discriminator types `properties`. |
220
+ | `properties` | [ComponentProperties](#componentproperties) | Yes | Type-specific properties. TS-side: each `type` maps to a matching `Component*Properties` variant. |
221
+ | `conditions` | [FlowConditionConfig](#flowconditionconfig) | No | Condition for showing/hiding the component |
222
+ | `components` | [Component](#component)[] | No | Child component templates (used by `group` and `repeater`) |
223
+ | `value` | _any_ | No | _Runtime only._ Current value |
224
+ | `addedComponents` | [Component](#component)[][] | No | _Runtime only._ Group/repeater iterations. Do not set in authored JSON |
225
+ | `valid` | `boolean` | No | _Runtime only._ Do not set in authored JSON |
226
+ | `display` | `object` | No | _Runtime only._ Display overrides. Do not set in authored JSON |
227
+
228
+ ### Component Types
229
+
230
+ | Type | Category | Description |
231
+ | --------------- | ----------- | ------------------------------------------------------------------------- |
232
+ | `header` | Display | Section heading |
233
+ | `text` | Display | Static text block |
234
+ | `divider` | Display | Visual separator with optional label |
235
+ | `callout` | Display | Styled alert/info box with variant coloring and optional icon |
236
+ | `table` | Display | Static comparison/data table with optional column highlighting |
237
+ | `inputText` | Input | Single-line text input |
238
+ | `inputTextArea` | Input | Multi-line text input |
239
+ | `inputNumber` | Input | Numeric input (supports optional decimal restriction and start adornment) |
240
+ | `dropDown` | Selection | Single-select dropdown |
241
+ | `dropDownMulti` | Selection | Multi-select dropdown |
242
+ | `checkbox` | Selection | Checkbox group |
243
+ | `radio` | Selection | Radio button group |
244
+ | `toggleSwitch` | Selection | Boolean toggle |
245
+ | `yesNo` | Selection | Two large tappable buttons for binary yes/no selection |
246
+ | `confirm` | Selection | Single checkbox for consent / opt-in (value is `true` when ticked, cleared when unticked) |
247
+ | `date` | Date & Time | Calendar popup date picker |
248
+ | `time` | Date & Time | Hour/minute/AM-PM time selector |
249
+ | `dateTime` | Date & Time | Combined calendar + time picker |
250
+ | `dateRange` | Date & Time | Two calendar pickers for start/end dates |
251
+ | `timeRange` | Date & Time | Two time selectors for start/end times |
252
+ | `dateTimeRange` | Date & Time | Two datetime pickers for start/end |
253
+ | `fileUpload` | Interactive | File upload |
254
+ | `rating` | Interactive | Star rating |
255
+ | `slider` | Interactive | Range slider |
256
+ | `colorPicker` | Interactive | Saturation/hue picker with hex input and optional swatches |
257
+ | `cardSelect` | Selection | Card-based single-select with optional price, features, and badge |
258
+ | `group` | Container | Groups child components visually (fieldset + condition grouping) |
259
+ | `repeater` | Container | Repeatable container — users can add/remove iterations of child components |
260
+ | `computed` | Computed | Displays a formula-evaluated result. Inside a repeater, evaluates per-iteration |
261
+ | `signature` | Interactive | Captures a hand-drawn or typed signature. Stores base64 PNG (draw) or text (type) |
262
+
263
+ ---
264
+
265
+ ## ComponentProperties
266
+
267
+ Properties vary by component type. All fields are optional; which ones are relevant depends on the component `type`.
268
+
269
+ ### Common Properties
270
+
271
+ | Field | Type | Applicable Types | Description |
272
+ | ------------- | ---------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
273
+ | `label` | `string` | All | Display label |
274
+ | `required` | `boolean` | All input/selection types | Field must have a value to pass validation |
275
+ | `placeholder` | `string` | Text inputs | Placeholder text when empty (dropdowns render a fixed built-in placeholder) |
276
+ | `helperText` | `string` | All input/selection types | Instructional text below the field |
277
+ | `tooltip` | `string` | All | Tooltip on hover/focus of info icon |
278
+ | `detail` | `string` | All | Rich text displayed above the component. Supports markup (`[b]`, `[i]`, `[l]`, `[s size="sm|lg|xl"]`). When set, hides the label unless `showLabel` is true |
279
+ | `width` | `ComponentWidth` | All | Component width for flow-based layout. See [Width](#width) |
280
+
281
+ ### Display Component Properties
282
+
283
+ | Field | Type | Applicable Types | Description |
284
+ | ------------------ | ------------------------------------------------- | --------------------------- | ------------------------------------------------------------------ |
285
+ | `value` | `string` | `header`, `text`, `divider`, `callout` | Static content value (supports markup on text/callout) |
286
+ | `displayType` | `boolean` | `text` | When `true`, renders as display-only (no input) |
287
+ | `textAlign` | `"left"` \| `"center"` \| `"right"` | `divider` | Text alignment for the label |
288
+ | `title` | `string` | `callout` | Bold header text for the callout |
289
+ | `variant` | `"info"` \| `"success"` \| `"warning"` \| `"neutral"` | `callout` | Color scheme (default `"info"`) |
290
+ | `icon` | `string` | `callout` | Icon key: `info`, `check`, `warning`, `question`, `lightbulb`, `megaphone`, `bell`, `shield`, `lock`, `heart`, `flag`, `bookmark`, `zap`, `pencil`, `star`, or `none`. Falls back to variant default if omitted |
291
+ | `label` | `string` | `table` | Optional title displayed above the table |
292
+ | `columns` | `TableColumn[]` | `table` | Column definitions: `{ label: string }[]` |
293
+ | `rows` | `TableRow[]` | `table` | Row definitions: `{ label: string, values: string[] }[]` |
294
+ | `highlightColumn` | `integer` | `table` | 1-based column number to highlight (0 = none) |
295
+
296
+ ### Computed Component Properties
297
+
298
+ | Field | Type | Description |
299
+ | ---------------- | -------------------------------------------- | -------------------------------------------------------------------------- |
300
+ | `label` | `string` | Display label for the computed value |
301
+ | `formula` | `string` | Formula expression. References fields via `{uuid}`, supports `+`, `-`, `*`, `/`, `SUM()`, `COUNT()`, `AVG()`, `MIN()`, `MAX()`, `IF()`, comparison operators, and `.selectedOption.metadata.key` |
302
+ | `format` | `"number"` \| `"currency"` \| `"percentage"` | Display format for the result (default `"number"`) |
303
+ | `decimalPlaces` | `integer` | Decimal places (0-10, default 2) |
304
+ | `currencySymbol` | `string` | Currency symbol when format is `"currency"` (default `"$"`) |
305
+ | `showLabel` | `boolean` | Whether to display the label (default `true`) |
306
+ | `detail` | `string` | Rich text description displayed above the computed value |
307
+ | `width` | `ComponentWidth` | Layout width |
308
+
309
+ Inside a repeater, formula references to sibling template UUIDs resolve to the current iteration's values. Aggregation functions (`SUM`, `COUNT`, `AVG`, `MIN`, `MAX`) still aggregate across all iterations. Outside a repeater, the computed component evaluates once using standard field resolution.
310
+
311
+ ### Signature Properties
312
+
313
+ | Field | Type | Description |
314
+ | ----------- | -------------------------------------- | ------------------------------------------------------------------------------------ |
315
+ | `label` | `string` | Display label (default `"Signature"`) |
316
+ | `showLabel` | `boolean` | Whether to display the label |
317
+ | `detail` | `string` | Rich text description above the signature pad |
318
+ | `mode` | `"draw"` \| `"type"` \| `"both"` | Draw = canvas pad, Type = typed name in script font, Both = toggle between modes |
319
+ | `required` | `boolean` | Whether a signature is required |
320
+ | `width` | `ComponentWidth` | Layout width |
321
+
322
+ Draw mode stores the signature as a base64 PNG data URL. Type mode stores the typed name as a plain string.
323
+
324
+ ### Text Input Properties
325
+
326
+ | Field | Type | Applicable Types | Description |
327
+ | -------------------- | ----------------------------------------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
328
+ | `regex` | `string` | `inputText`, `inputTextArea` | Regular expression for validation |
329
+ | `maxlength` | `integer` | `inputText`, `inputTextArea` | Maximum character length |
330
+ | `startAdornment` | `string` | `inputText`, `inputNumber` | Text/symbol at the start of the field (e.g. `$`, `+1`) |
331
+ | `decimalPlaces` | `integer` | `inputNumber` | When set, restricts input to a fixed number of decimal places (0-10). Uses controlled text input with keystroke filtering |
332
+ | `min` | `number` | `inputNumber` | Minimum allowed value. Sets HTML `min` attribute (constrains stepper arrows) and clamps value on blur |
333
+ | `max` | `number` | `inputNumber` | Maximum allowed value. Sets HTML `max` attribute (constrains stepper arrows) and clamps value on blur |
334
+ | `inputType` | `"text"` \| `"email"` \| `"tel"` \| `"url"` \| `"password"` | `inputText` | HTML input type hint. Controls mobile keyboard behavior and input masking. Default `"text"` |
335
+ | `readOnly` | `boolean` | `inputText`, `inputTextArea`, `inputNumber`, `dropDown`, `dropDownMulti`, `radio`, `checkbox`, `slider`, `date`, `time`, `dateTime` | When `true`, the field is non-editable with a muted background. Useful for locking pricing/values so users can see but not modify |
336
+ | `autocomplete` | `string` | `inputText`, `inputTextArea`, `inputNumber` | HTML `autocomplete` attribute value for browser autofill (e.g. `"email"`, `"tel"`, `"given-name"`) |
337
+ | `showPasswordToggle` | `boolean` | `inputText` | When `true` and `inputType` is `"password"`, shows an eye icon to toggle password visibility |
338
+
339
+ ### Selection Component Properties
340
+
341
+ | Field | Type | Applicable Types | Description |
342
+ | -------------- | ----------------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
343
+ | `options` | [Option](#option)[] | `dropDown`, `dropDownMulti`, `checkbox`, `radio` | Available choices |
344
+ | `defaultValue` | `string` \| `"yes"` \| `"no"` | `yesNo`, `radio`, `cardSelect`, `dropDown` | Pre-selected option on first render. For `yesNo` use `"yes"` or `"no"`; for the others use the matching option `value`. Ignored when no option matches. Without a matching `defaultValue`, all of these start at `null` — there is no default-to-first-option behavior. |
345
+
346
+ ### Slider Properties
347
+
348
+ | Field | Type | Description |
349
+ | ----------- | --------- | --------------- |
350
+ | `min` | `number` | Minimum value |
351
+ | `max` | `number` | Maximum value |
352
+ | `steps` | `number` | Step increment |
353
+ | `marks` | `boolean` | Show tick marks |
354
+ | `initValue` | `number` | Initial value |
355
+
356
+ ### Rating Properties
357
+
358
+ | Field | Type | Description |
359
+ | ----------- | -------- | ----------------------------------------------------------------- |
360
+ | `max` | `number` | Maximum rating value |
361
+ | `precision` | `number` | Rating precision (e.g. `0.5` for half-stars, `1` for whole stars) |
362
+ | `icon` | `string` | Icon shape: `star`, `heart`, `thumbsUp`, `circle`, or `diamond` (default `"star"`) |
363
+
364
+ ### File Upload Properties
365
+
366
+ | Field | Type | Description |
367
+ | --------- | --------- | ------------------------------------------------------- |
368
+ | `accept` | `string` | Comma-separated file extensions (e.g. `.pdf,.jpg,.png`) |
369
+ | `maxSize` | `integer` | Maximum file size in bytes |
370
+
371
+ ### Group Properties
372
+
373
+ | Field | Type | Description |
374
+ | ------------- | --------- | ------------------------------------------------------------------------------------------------------------ |
375
+ | `showLabel` | `boolean` | Show the component label even when detail text is set. For groups, shows the group label as a visible header |
376
+ | `collapsible` | `boolean` | Allow the group to be collapsed/expanded |
377
+ | `showBorder` | `boolean` | Draw the container border/frame around the group |
378
+
379
+ ### Repeater Properties
380
+
381
+ | Field | Type | Description |
382
+ | --------------- | --------- | --------------------------------------------------------------------------------------- |
383
+ | `showLabel` | `boolean` | Show the repeater label as a visible header |
384
+ | `collapsible` | `boolean` | Allow each iteration to be collapsed/expanded |
385
+ | `showBorder` | `boolean` | Draw the container border/frame around the repeater |
386
+ | `minIterations` | `integer` | Minimum number of rows (also initial count). Default `1`. Remove button hidden at minimum |
387
+ | `initialData` | `array` | Pre-populated data for rows. Each element maps template child UUIDs to initial values |
388
+
389
+ Repeaters are containers that support multiple iterations — users can add and remove rows of child components. Groups are purely visual containers (fieldset + condition grouping).
390
+
391
+ #### Nesting Rules
392
+
393
+ - Groups inside repeaters: allowed
394
+ - Repeaters inside groups: allowed
395
+ - Repeaters inside repeaters: **not** allowed
396
+
397
+ #### Migration
398
+
399
+ Legacy `group` components with `repeatable: true` must be migrated to `type: "repeater"` before loading.
400
+
401
+ ### Date & Time Properties
402
+
403
+ | Field | Type | Applicable Types | Description |
404
+ | ------------------ | ------------ | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
405
+ | `placeholder` | `string` | `date`, `time`, `dateTime` | Placeholder text when empty |
406
+ | `placeholderStart` | `string` | `dateRange`, `timeRange`, `dateTimeRange` | Placeholder text for the start field |
407
+ | `placeholderEnd` | `string` | `dateRange`, `timeRange`, `dateTimeRange` | Placeholder text for the end field |
408
+ | `min` | `string` | All date/time types | Minimum allowed value. Accepts ISO date (`YYYY-MM-DD`), relative expression (`today`, `today+7`, `today-3`), or time (`HH:MM`) |
409
+ | `max` | `string` | All date/time types | Maximum allowed value. Same formats as `min` |
410
+ | `dateFormat` | `DateFormat` | `date`, `dateTime`, `dateRange`, `dateTimeRange` | Display format for dates. See [Date Format](#date-format). Default `"MM/DD/YYYY"` |
411
+ | `minTime` | `string` | `dateTime`, `dateTimeRange` | Minimum allowed time (`HH:MM`, 24h). Enforced independently from `min` date |
412
+ | `maxTime` | `string` | `dateTime`, `dateTimeRange` | Maximum allowed time (`HH:MM`, 24h). Enforced independently from `max` date |
413
+ | `step` | `number` | `time`, `dateTime`, `timeRange`, `dateTimeRange` | Minute interval for time selection. Default `15` |
414
+
415
+ #### Date Format
416
+
417
+ | Value | Example |
418
+ | -------------- | ---------------------- |
419
+ | `"MM/DD/YYYY"` | `02/17/2026` (default) |
420
+ | `"DD/MM/YYYY"` | `17/02/2026` |
421
+ | `"YYYY-MM-DD"` | `2026-02-17` |
422
+
423
+ #### Relative Date Constraints
424
+
425
+ The `min` and `max` properties on date-containing types accept relative expressions:
426
+
427
+ | Expression | Meaning |
428
+ | ----------- | ------------------------------------------------------- |
429
+ | `"today"` | Today's date |
430
+ | `"today+N"` | N days from today (e.g. `"today+14"` = two weeks ahead) |
431
+ | `"today-N"` | N days before today (e.g. `"today-7"` = one week ago) |
432
+
433
+ Fixed ISO dates (e.g. `"2026-01-01"`) continue to work as before. Relative expressions are resolved at render time in FBRE.
434
+
435
+ #### Value Formats
436
+
437
+ | Type | Value Format | Example |
438
+ | --------------- | -------------------- | ------------------------------------------------------------ |
439
+ | `date` | `"YYYY-MM-DD"` | `"2026-02-17"` |
440
+ | `time` | `"HH:MM"` (24h) | `"14:30"` |
441
+ | `dateTime` | `"YYYY-MM-DDTHH:MM"` | `"2026-02-17T14:30"` |
442
+ | `dateRange` | `{ start, end }` | `{ "start": "2026-02-17", "end": "2026-02-20" }` |
443
+ | `timeRange` | `{ start, end }` | `{ "start": "09:00", "end": "17:00" }` |
444
+ | `dateTimeRange` | `{ start, end }` | `{ "start": "2026-02-17T09:00", "end": "2026-02-20T17:00" }` |
445
+
446
+ ### Yes/No Properties
447
+
448
+ | Field | Type | Description |
449
+ | ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
450
+ | `labelYes` | `string` | Custom label for the "Yes" button. Default `"Yes"` |
451
+ | `labelNo` | `string` | Custom label for the "No" button. Default `"No"` |
452
+ | `layout` | `string` | Button layout direction: `"horizontal"` (side-by-side) or `"vertical"` (stacked). Omit for responsive default (adapts to width) |
453
+
454
+ Value is `"yes"` or `"no"` (string).
455
+
456
+ ### Color Picker Properties
457
+
458
+ | Field | Type | Description |
459
+ | -------------- | ---------- | ----------------------------------------------------------------- |
460
+ | `swatches` | `string[]` | Preset color swatches (hex format, e.g. `["#FF0000", "#00FF00"]`) |
461
+ | `defaultValue` | `string` | Default color value (hex format, e.g. `"#1976d2"`) |
462
+
463
+ Value is a hex color string (e.g. `"#FF5733"`).
464
+
465
+ ### Card Select Properties
466
+
467
+ | Field | Type | Description |
468
+ | --------- | --------------------------------------- | ----------------------------------------------- |
469
+ | `options` | [CardSelectOption](#cardselectoption)[] | Array of card options to display |
470
+ | `columns` | `integer` | Number of columns in the card grid. Default `2` |
471
+
472
+ Value is the `value` string of the selected card option.
473
+
474
+ #### CardSelectOption
475
+
476
+ | Field | Type | Required | Description |
477
+ | ------------- | ---------- | -------- | ------------------------------------------------------------ |
478
+ | `label` | `string` | Yes | Display title for the card |
479
+ | `value` | `string` | Yes | Value stored when selected |
480
+ | `description` | `string` | No | Short description below the title |
481
+ | `title` | `string` | No | Heading text displayed prominently on the card |
482
+ | `features` | `string[]` | No | Feature strings displayed as a checklist |
483
+ | `badge` | `string` | No | Badge text shown as a pill above the card (e.g. `"Popular"`) |
484
+ | `metadata` | `object` | No | Arbitrary key-value pairs for calculations |
485
+
486
+ #### Card Select Example
487
+
488
+ ```json
489
+ {
490
+ "type": "cardSelect",
491
+ "properties": {
492
+ "label": "Plan",
493
+ "showLabel": false,
494
+ "options": [
495
+ {
496
+ "label": "Pro",
497
+ "value": "pro",
498
+ "title": "$29/mo",
499
+ "features": ["20 flows", "1,000 submissions/mo"]
500
+ },
501
+ {
502
+ "label": "Business",
503
+ "value": "business",
504
+ "title": "$79/mo",
505
+ "badge": "Popular",
506
+ "features": ["100 flows", "5,000 submissions/mo"]
507
+ }
508
+ ]
509
+ }
510
+ }
511
+ ```
512
+
513
+ ---
514
+
515
+ ## Option
516
+
517
+ A selectable option used by `dropDown`, `dropDownMulti`, `checkbox`, and `radio` components.
518
+
519
+ | Field | Type | Required | Description |
520
+ | ---------- | --------------------------------------------- | -------- | --------------------------------------------------------------------------------------------- |
521
+ | `label` | `string` | Yes | Display text |
522
+ | `value` | `string` \| `number` | Yes | Value stored when selected |
523
+ | `metadata` | `Record<string, string \| number \| boolean>` | No | Structured key-value metadata (e.g. price, weight, unit). Consumed by the calculations engine |
524
+
525
+ ### Option Metadata Example
526
+
527
+ ```json
528
+ {
529
+ "type": "dropDown",
530
+ "properties": {
531
+ "label": "Material",
532
+ "options": [
533
+ {
534
+ "label": "Standard Steel",
535
+ "value": "steel",
536
+ "metadata": { "pricePerUnit": 12.50, "unit": "sqft" }
537
+ },
538
+ {
539
+ "label": "Premium Aluminum",
540
+ "value": "aluminum",
541
+ "metadata": { "pricePerUnit": 24.00, "unit": "sqft" }
542
+ }
543
+ ]
544
+ }
545
+ }
546
+ ```
547
+
548
+ ---
549
+
550
+ ## Width
551
+
552
+ Components use a flow-based layout system where each component declares its own width. Components flow left-to-right and wrap naturally, like words in a paragraph. This works at both the screen level and inside groups.
553
+
554
+ ### ComponentWidth
555
+
556
+ | Value | CSS Width | Description |
557
+ | ------------------ | --------- | --------------------------------- |
558
+ | `"full"` | `100%` | Full width (default when omitted) |
559
+ | `"three-quarters"` | `75%` | Three quarters width |
560
+ | `"two-thirds"` | `66.67%` | Two thirds width |
561
+ | `"half"` | `50%` | Half width |
562
+ | `"third"` | `33.33%` | One third width |
563
+ | `"quarter"` | `25%` | Quarter width |
564
+
565
+ ### Width Example
566
+
567
+ ```json
568
+ {
569
+ "type": "group",
570
+ "properties": { "label": "Name" },
571
+ "components": [
572
+ {
573
+ "type": "inputText",
574
+ "properties": { "label": "First Name", "width": "half" }
575
+ },
576
+ {
577
+ "type": "inputText",
578
+ "properties": { "label": "Last Name", "width": "half" }
579
+ }
580
+ ]
581
+ }
582
+ ```
583
+
584
+ ### Migration
585
+
586
+ Legacy group `layout` strings (e.g. `"2: 50,50"`) must be migrated to per-child `width` values before loading. The `layout` property is no longer supported.
587
+
588
+ ---
589
+
590
+ ## Validation
591
+
592
+ Components can have validation rules defined in `properties.validation`. This replaces the legacy `required` and `regex` flat properties. Legacy formats must be migrated before loading.
593
+
594
+ ### FlowValidationConfig
595
+
596
+ | Field | Type | Required | Description |
597
+ | ------- | ----------------------------------- | -------- | -------------------------------- |
598
+ | `rules` | [ValidationRule](#validationrule)[] | Yes | Ordered list of validation rules |
599
+
600
+ ### ValidationRule
601
+
602
+ | Field | Type | Required | Description |
603
+ | --------- | -------- | -------- | --------------------------------------------------------------- |
604
+ | `type` | `string` | Yes | Rule type (see [Validation Rule Types](#validation-rule-types)) |
605
+ | `params` | `object` | No | Type-specific parameters |
606
+ | `message` | `string` | No | Custom error message (default message used when omitted) |
607
+
608
+ ### Validation Rule Types
609
+
610
+ | Type | Params | Default Message | Applicable Types |
611
+ | -------------- | --------------------- | ------------------------------------------ | ------------------------------------------- |
612
+ | `required` | — | "This field is required" | All input/selection types |
613
+ | `email` | — | "Please enter a valid email address" | `inputText` |
614
+ | `phone` | — | "Please enter a valid phone number" | `inputText` |
615
+ | `url` | — | "Please enter a valid URL" | `inputText` |
616
+ | `minLength` | `{ min: number }` | "Must be at least N characters" | `inputText`, `inputTextArea` |
617
+ | `maxLength` | `{ max: number }` | "Must be no more than N characters" | `inputText`, `inputTextArea` |
618
+ | `exactLength` | `{ length: number }` | "Must be exactly N characters" | `inputText`, `inputTextArea` |
619
+ | `minValue` | `{ min: number }` | "Must be at least N" | `inputNumber` |
620
+ | `maxValue` | `{ max: number }` | "Must be no more than N" | `inputNumber` |
621
+ | `pattern` | `{ regex: string }` | "Value does not match the required format" | `inputText`, `inputTextArea` |
622
+ | `minSelected` | `{ min: number }` | "Select at least N options" | `dropDownMulti`, `checkbox` |
623
+ | `maxSelected` | `{ max: number }` | "Select no more than N options" | `dropDownMulti`, `checkbox` |
624
+ | `fileType` | `{ types: string[] }` | "File type is not allowed" | `fileUpload` |
625
+ | `fileSize` | `{ max: number }` | "File must be smaller than N" | `fileUpload` |
626
+ | `contains` | `{ text: string }` | "Must contain \"text\"" | `inputText`, `inputTextArea` |
627
+ | `excludes` | `{ text: string }` | "Must not contain \"text\"" | `inputText`, `inputTextArea` |
628
+ | `matchesField` | `{ field: string }` | "Fields must match" | `inputText`, `inputTextArea`, `inputNumber` |
629
+
630
+ ### Validation Example
631
+
632
+ ```json
633
+ {
634
+ "validation": {
635
+ "rules": [
636
+ { "type": "required" },
637
+ { "type": "email" },
638
+ {
639
+ "type": "minLength",
640
+ "params": { "min": 5 },
641
+ "message": "Email must be at least 5 characters"
642
+ }
643
+ ]
644
+ }
645
+ }
646
+ ```
647
+
648
+ ### Error Display
649
+
650
+ When validation fails, the first failing error message is shown below the field. If multiple rules fail, an "(and N more)" indicator is appended.
651
+
652
+ ### Migration
653
+
654
+ Legacy `required` and `regex` properties must be migrated to `FlowValidationConfig` before loading.:
655
+
656
+ - `{ required: true }` → `{ validation: { rules: [{ type: "required" }] } }`
657
+ - `{ regex: "..." }` → `{ validation: { rules: [{ type: "pattern", params: { regex: "..." } }] } }`
658
+
659
+ ---
660
+
661
+ ## Screen Transitions
662
+
663
+ Animated transitions between screens can be enabled via `config.navigation.transition`. When absent or set to `"none"`, screen changes are instant (zero overhead).
664
+
665
+ ### ScreenTransitionType
666
+
667
+ | Value | Effect | Direction-aware? |
668
+ | ------------- | ---------------------------------- | ---------------- |
669
+ | `"none"` | Instant swap (default) | — |
670
+ | `"slide"` | Full horizontal slide left/right | Yes |
671
+ | `"fade"` | Crossfade between screens | No |
672
+ | `"slideFade"` | 30px horizontal slide with opacity | Yes |
673
+ | `"rise"` | Vertical rise up / sink down | Yes |
674
+ | `"scaleFade"` | Scale 0.95→1 / 1→1.05 with opacity | No |
675
+
676
+ Direction-aware transitions reverse their animation when navigating backward.
677
+
678
+ ### Example
679
+
680
+ ```json
681
+ {
682
+ "config": {
683
+ "navigation": { "transition": "slideFade" }
684
+ }
685
+ }
686
+ ```
687
+
688
+ ### CSS Custom Properties
689
+
690
+ | Property | Default | Description |
691
+ | ---------------------------- | ------------------------------ | ---------------------- |
692
+ | `--fbre-transition-duration` | `250ms` | Animation duration |
693
+ | `--fbre-transition-easing` | `cubic-bezier(0.4, 0, 0.2, 1)` | Animation easing curve |
694
+
695
+ `@media (prefers-reduced-motion: reduce)` sets the duration to `0ms` automatically.
696
+
697
+ ---
698
+
699
+ ## Conditions
700
+
701
+ Conditions allow components and screens to be shown or hidden based on the runtime value of other components.
702
+
703
+ ### FlowConditionConfig
704
+
705
+ | Field | Type | Required | Description |
706
+ | -------- | --------------------------------- | -------- | ----------------------------------------------------------------------- |
707
+ | `action` | `"show"` \| `"hide"` | Yes | `show` = visible when condition met; `hide` = hidden when condition met |
708
+ | `when` | [ConditionGroup](#conditiongroup) | Yes | The condition group to evaluate |
709
+
710
+ ### ConditionGroup
711
+
712
+ | Field | Type | Required | Description |
713
+ | ------- | --------------------------------- | -------- | ----------------------------------------------------- |
714
+ | `logic` | `"and"` \| `"or"` | Yes | `and` = all rules must match; `or` = any rule matches |
715
+ | `rules` | [ConditionRule](#conditionrule)[] | Yes | One or more rules (minimum 1) |
716
+
717
+ ### ConditionRule
718
+
719
+ | Field | Type | Required | Description |
720
+ | ------------ | ------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
721
+ | `source` | `string` | Yes | UUID of the source component, or a context key when `sourceType` is `"context"` |
722
+ | `sourceType` | `"component"` \| `"context"` | No | Where to resolve the source. `"component"` (default) looks up a component UUID. `"context"` looks up a key in FBRE's `context` prop |
723
+ | `operator` | `string` | Yes | Comparison operator (see [Operators](#operators)) |
724
+ | `value` | `string` \| `number` \| `boolean` \| `string[]` \| `number[]` | No | Comparison value. Omitted for unary operators |
725
+
726
+ #### External Context Conditions
727
+
728
+ When `sourceType` is `"context"`, the rule evaluates against a value from FBRE's `context` prop rather than a component UUID. This allows conditions based on external application state.
729
+
730
+ ```jsx
731
+ <FBRE
732
+ flow={flow}
733
+ context={{ isInvite: true, userTier: "pro" }}
734
+ onFlowComplete={handleComplete}
735
+ />
736
+ ```
737
+
738
+ ```json
739
+ {
740
+ "conditions": {
741
+ "action": "hide",
742
+ "when": {
743
+ "logic": "and",
744
+ "rules": [
745
+ { "source": "isInvite", "sourceType": "context", "operator": "isTrue" }
746
+ ]
747
+ }
748
+ }
749
+ }
750
+ ```
751
+
752
+ ### Operators
753
+
754
+ | Operator | Category | Expects Value | Description |
755
+ | -------------------- | -------- | ------------- | --------------------------------------------------------- |
756
+ | `equals` | Equality | Yes | Exact match |
757
+ | `notEquals` | Equality | Yes | Not an exact match |
758
+ | `contains` | String | Yes | Source contains the value substring |
759
+ | `notContains` | String | Yes | Source does not contain the value substring |
760
+ | `startsWith` | String | Yes | Source starts with the value |
761
+ | `endsWith` | String | Yes | Source ends with the value |
762
+ | `isEmpty` | Presence | No | Source has no value |
763
+ | `isNotEmpty` | Presence | No | Source has a value |
764
+ | `greaterThan` | Numeric | Yes | Source > value |
765
+ | `greaterThanOrEqual` | Numeric | Yes | Source >= value |
766
+ | `lessThan` | Numeric | Yes | Source < value |
767
+ | `lessThanOrEqual` | Numeric | Yes | Source <= value |
768
+ | `isOneOf` | Set | Yes (array) | Source value is in the provided array |
769
+ | `isNotOneOf` | Set | Yes (array) | Source value is not in the provided array |
770
+ | `includesAny` | Set | Yes (array) | Source (multi-value) includes any of the provided values |
771
+ | `includesAll` | Set | Yes (array) | Source (multi-value) includes all of the provided values |
772
+ | `includesNone` | Set | Yes (array) | Source (multi-value) includes none of the provided values |
773
+ | `isTrue` | Boolean | No | Source is truthy |
774
+ | `isFalse` | Boolean | No | Source is falsy |
775
+
776
+ ---
777
+
778
+ ## FlowCalculation
779
+
780
+ Top-level calculations are global formulas not tied to any screen. They compute values reactively from component inputs, option metadata, and other calculations.
781
+
782
+ | Field | Type | Required | Description |
783
+ | ---------------- | ------------------- | -------- | -------------------------------------------------------------- |
784
+ | `uuid` | `string` | Yes | Unique identifier for the calculation |
785
+ | `label` | `string` | Yes | Human-readable label |
786
+ | `formula` | `string` | Yes | Formula expression (see syntax below) |
787
+ | `format` | `CalculationFormat` | No | Display format: `"number"`, `"currency"`, or `"percentage"` |
788
+ | `decimalPlaces` | `integer` | No | Number of decimal places (0–10) |
789
+ | `currencySymbol` | `string` | No | Currency symbol when format is `"currency"` (defaults to `$`) |
790
+
791
+ ### Formula Syntax
792
+
793
+ | Syntax | Description |
794
+ | --------------------------------------------- | --------------------------------------------------------------- |
795
+ | `{uuid}` | Component value reference |
796
+ | `{uuid}.selectedOption.metadata.key` | Selected option's metadata value |
797
+ | `SUM({uuid})` | Sum across repeater iterations |
798
+ | `COUNT({uuid})` | Count of repeater iterations |
799
+ | `AVG({uuid})` | Average across repeater iterations |
800
+ | `MIN({uuid})` | Minimum across repeater iterations |
801
+ | `MAX({uuid})` | Maximum across repeater iterations |
802
+ | `MIN(expr, expr, ...)` | Scalar minimum of N expressions (e.g. discount capping) |
803
+ | `MAX(expr, expr, ...)` | Scalar maximum of N expressions (e.g. minimum charge) |
804
+ | `IF(cond, then, else)` | Conditional — returns `then` when `cond != 0`, else `else` |
805
+ | `> < >= <= == !=` | Comparison operators (return `1` for true, `0` for false) |
806
+ | `+ - * /` | Arithmetic operators |
807
+ | `( )` | Grouping / precedence |
808
+ | Numeric literals | Constants (e.g. `0.08`, `100`) |
809
+
810
+ Formulas return `null` when any referenced field is empty or unresolvable. Calculations can reference other calculations by UUID; evaluation follows topological order.
811
+
812
+ ### Example
813
+
814
+ ```json
815
+ {
816
+ "calculations": [
817
+ {
818
+ "uuid": "calc-subtotal",
819
+ "label": "Subtotal",
820
+ "formula": "SUM({line-total-uuid})",
821
+ "format": "currency",
822
+ "decimalPlaces": 2,
823
+ "currencySymbol": "$"
824
+ },
825
+ {
826
+ "uuid": "calc-tax",
827
+ "label": "Tax Amount",
828
+ "formula": "{calc-subtotal} * 0.08",
829
+ "format": "currency",
830
+ "decimalPlaces": 2,
831
+ "currencySymbol": "$"
832
+ }
833
+ ]
834
+ }
835
+ ```
836
+
837
+ ---
838
+
839
+ ## Reference Markup
840
+
841
+ Text properties can include `${...}` references that resolve at render time. Resolution tries, in order: calculation results, component values, then keys from FBRE's `context` prop. References are replaced with the resolved value when the form is displayed.
842
+
843
+ ### Syntax
844
+
845
+ | Pattern | Resolves To | Example |
846
+ | --- | --- | --- |
847
+ | `${calculation-uuid}` | Formatted calculation result | `${calc-456}` → `"$1,247.50"` |
848
+ | `${component-uuid}` | Component's current value | `${abc-123}` → `"John Smith"` |
849
+ | `${context-key}` | Value from the FBRE `context` prop | `${accountName}` → `"Acme Inc."` |
850
+
851
+ ### Supported Surfaces
852
+
853
+ References are supported in the following component properties:
854
+
855
+ | Surface | Property | Resolution |
856
+ | --- | --- | --- |
857
+ | Display Text | `value` | HTML (within markup) |
858
+ | Header | `value` | Plain text |
859
+ | Callout | `title`, `value` | title: plain text, value: HTML |
860
+ | Field labels | `label` | Plain text |
861
+ | Field descriptions | `detail` | HTML (within markup) |
862
+ | Helper text | `helperText` | Plain text |
863
+ | Placeholders | `placeholder` | Plain text |
864
+ | Screen labels | `label` | Plain text |
865
+
866
+ ### Example
867
+
868
+ ```json
869
+ {
870
+ "type": "text",
871
+ "properties": {
872
+ "value": "Your total is ${calc-total} for ${service-type-uuid} service."
873
+ }
874
+ }
875
+ ```