Style System
Styles are declared in the style object of any visual component, grouped into named domains. Domains are applied independently — you may use any combination.
"style": {"layout": { "maxWidth": "infinity", "padding": { "horizontal": 16 } },"common": { "foreground": { "color": "white" }, "cornerRadius": 12 },"navigation": { "navigationTitle": "My Screen" },"animation": { "kind": "spring", "value": "${iconScale}", "duration": 1.0 }}7.1 style.common
Section titled “7.1 style.common”| Property | Type / Values | Description |
|---|---|---|
| foreground | color object or gradient | Text and icon foreground color. |
| background | color, material, gradient, or component | Background fill. See §7.5 for all background forms. |
| font | string preset or font object | Font style. See §7.2. |
| cornerRadius | number | Corner radius in points. |
| opacity | number 0–1 or expr | Component opacity. |
| scale | number or expr | Scales the rendered component. Animatable via style.animation. |
| overlay | component | Renders a component as an overlay on top of this component. |
| tint | color value | Tint color applied to the component. |
| disabled | bool or expr | When truthy, renders the component in a disabled (greyed-out, non-interactive) state. |
| glass | string or expr | iOS 26 liquid glass effect. See §7.26. |
7.2 Font Values
Section titled “7.2 Font Values”| Form | Example | Notes |
|---|---|---|
| String preset | ”headline” | Presets: largeTitle, title, title2, headline, body, callout, subheadline, footnote, caption. |
| System font | { “kind”: “system”, “size”: 16 } | Custom-size system font. |
| Named + weight | { “kind”: “title”, “weight”: “bold” } | Weights: ultraLight, light, regular, medium, semibold, bold, heavy, black. |
7.3 Color Values
Section titled “7.3 Color Values”Supported color keywords (closed list)
Section titled “Supported color keywords (closed list)”A bare-string color keyword MUST be one of the following. Anything else is treated as an unrecognised string and fails validation.
Semantic / adaptive: primary, secondary, clear, accentColor, background, surface, surfaceVariant, onSurface, onSurfaceVariant, outline, error.
Named: blue, white, black, green, red, yellow, orange, purple, gray, cyan, mint, pink, indigo, teal, brown.
Keyword matching is case-insensitive (accentcolor and accentColor both work).
| Form | Example | Notes |
|---|---|---|
| System keyword | ”primary” | One of the closed-list keywords above. |
| Hex string | ”#4A90D9” | 3-digit (#RGB), 6-digit (#RRGGBB), or 8-digit (#RRGGBBAA) hex, case-insensitive. |
| State ref | ”${iconColor}“ | Color value stored in state. |
| Expression | ”{{ ${isError} ? ‘red’ : ‘green’ }}“ | Computed color from an expression. Result string must itself be a keyword or hex. |
| Color + opacity | { “color”: “blue”, “opacity”: 0.5 } | Any color form with a fractional opacity (0–1). Applies to both named and hex colors. |
| Adaptive (light/dark) | { “light”: “white”, “dark”: “black” } | System-resolved color: uses “light” value in light mode, “dark” value in dark mode. |
| Adaptive + opacity | { “light”: “white”, “dark”: “black”, “opacity”: 0.8 } | Adaptive color with opacity applied after trait resolution. |
"foreground": "blue""foreground": { "color": "${textColor}" }"foreground": { "color": "#4A90D9", "opacity": 0.8 }"foreground": { "light": "black", "dark": "white" }"foreground": { "light": "#1A1A1A", "dark": "#F5F5F5", "opacity": 0.9 }"shadow": { "color": { "color": "black", "opacity": 0.35 }, "radius": 8, "x": 0, "y": 4 }"stroke": { "content": { "color": "{{ #{orientation} == 'landscape' ? 'red' : 'yellow' }}" },"style": { "lineWidth": 5 } }Anti-patterns — NOT supported (will fail validation)
Section titled “Anti-patterns — NOT supported (will fail validation)”Do NOT use UIKit / SwiftUI semantic color names. They are NOT in the closed list above, render as literal strings, and validation rejects them:
label, secondaryLabel, tertiaryLabel, quaternaryLabel, placeholderText, separator, opaqueSeparator, link, systemBlue, systemRed, systemOrange, systemGreen, systemYellow, systemPink, systemPurple, systemTeal, systemIndigo, systemGray (and systemGray2 … systemGray6), systemBackground, secondarySystemBackground, tertiarySystemBackground, systemFill, secondarySystemFill, tertiarySystemFill, lightText, darkText.
Mapping iOS instincts to StemJSON:
| Want | Use |
|---|---|
Muted text / secondaryLabel | "secondary" |
Tertiary contrast / tertiaryLabel | { "color": "primary", "opacity": 0.6 } |
systemBlue accent | "accentColor" (inherits host tint) or "blue" |
systemBackground | "background" |
systemGray* shades | { "color": "gray", "opacity": 0.4–0.8 } or hex literals for exact values |
Programmatic refs (Color.blue, UIColor.systemBlue, .systemBackground) are not supported — bare keyword or hex only.
7.4 Gradient Values
Section titled “7.4 Gradient Values”| Type | Required fields |
|---|---|
| linear | colors (array), startPoint, endPoint |
| radial | colors (array), center, startRadius, endRadius |
| angular | colors (array), center, startAngle, endAngle |
"background": { "gradient": { "linear": {"colors": ["#1FA2FF", "#12D8FA"],"startPoint": "leading", "endPoint": "trailing" } } }7.5 Background Forms
Section titled “7.5 Background Forms”| Form | Example |
|---|---|
| Solid color | "background": { "color": "blue" } |
| Color + opacity | "background": { "color": "blue", "opacity": 0.5 } |
| Adaptive color | "background": { "light": "white", "dark": "#1C1C1E" } |
| Adaptive + opacity | "background": { "light": "white", "dark": "#1C1C1E", "opacity": 0.8 } |
| Plain string | "background": "blue" or "background": "#4A90D9" |
| Material | "background": { "material": "ultraThin" } |
| Color + material | "background": { "color": "blue", "material": "ultraThin" } |
| Gradient | "background": { "gradient": { "linear": { "colors": ["#A", "#B"], "startPoint": "top", "endPoint": "bottom" } } } |
| Component | "background": { "type": "template", "id": "...", "context": { "_source": "dp://..." } } |
⚠ Discriminator wrapper required. Background, foreground, and
style.shape.filldecode by looking up a single discriminator key on the dict:color,gradient, ormaterial. Writing"background": { "linear": {...} }directly is INVALID — the gradient value MUST be nested under thegradientkey as shown above. The same wrapper rule applies tostyle.common.foregroundandstyle.shape.fill(foreground does NOT accept materials).
ℹ Note: Power feature — background as a component: embed any shape or template as the background value to create rich animated backgrounds without native code.
7.6 style.layout
Section titled “7.6 style.layout”| Property | Type | Description |
|---|---|---|
| width | number | Fixed width in points. |
| height | number | Fixed height in points. |
| minWidth | number | Minimum width constraint. |
| minHeight | number | Minimum height constraint. |
| maxWidth | number or “infinity” | Maximum width. “infinity” expands to fill available space. |
| maxHeight | number or “infinity” | Maximum height. |
| alignment | string | Frame alignment when width/height constraints create extra space: leading | center | trailing | top | bottom | topLeading | topTrailing | bottomLeading | bottomTrailing. Default: center. |
| padding | object or number | Padding. Object: { top, bottom, leading, trailing, horizontal, vertical }. |
| offset | object | Positional offset: { x, y }. |
ℹ Note — frame alignment default is
center. WhenmaxWidthormaxHeightcreates a frame larger than the content’s intrinsic size, the content is centered within the frame by default. For text components that should be left-aligned, explicitly set"alignment": "leading". This is particularly important for text inside vstacks withmaxWidth: "infinity"— withoutalignment: "leading", single-line text will appear centered even if the parent vstack has_alignment: "leading"(the parent aligns the child’s frame, but the text within that frame still centers).
7.7 style.navigation
Section titled “7.7 style.navigation”| Property | Type | Description |
|---|---|---|
| navigationTitle | string or expr | Sets the navigation bar title. Supports context refs: ”@{item.name}“. |
| navigationBarTitleDisplayMode | string enum | Title display size: automatic |
| toolbarLeading | component | A component rendered in the leading (left) position of the navigation toolbar. |
| toolbarTrailing | component | A component rendered in the trailing (right) position of the navigation toolbar. |
"style": {"navigation": {"navigationTitle": "@{item.name}","navigationBarTitleDisplayMode": "large","toolbarTrailing": {"id": "close_btn", "type": "button","context": { "_label": "Done" },"events": { "onTap": [{ "state": { "id": "close_act", "input": { "onClose": true } } }] }}}}7.8 style.button
Section titled “7.8 style.button”// Standard preset:"style": { "button": { "standard": { "type": "borderedProminent", "shape": "roundedRectangle" } } }
// Custom button style:"style": {"button": {"custom": {"layout": { "maxWidth": "infinity", "minHeight": 44 },"common": { "foreground": { "color": "white" }, "cornerRadius": 10,"background": { "color": "blue" } }}}}Standard type values: plain, borderless, automatic, bordered, borderedProminent. Standard shape values: capsule, circle, automatic, roundedRectangle.
7.9 style.shape
Section titled “7.9 style.shape”Applied to shape components (circle, rectangle, roundedRectangle, star, bubble, capsule, ellipse) and embedded background shapes.
| Property | Type | Description |
|---|---|---|
| fill | solid color or gradient | Fill style. |
| stroke | object | Stroke: { “content”: …, “style”: { “lineWidth”: number } }. “content” accepts the same value forms as fill — a color string, { “light”: …, “dark”: … }, { “color”: … }, or { “gradient”: … }. A gradient stroke is { “content”: { “gradient”: { “linear”: … } } } — the gradient is the discriminator itself, never nested inside “color”. |
| trim | object | Path trim: { “from”: 0.0, “to”: 1.0 }. Used for progress-ring effects. |
| rotation | object | Rotation: { “angle”: number_or_expr, “anchor”: “center” }. Animatable. |
| inset | number | Insets the shape rendering within its frame. |
7.10 style.animation
Section titled “7.10 style.animation”| Property | Type | Description |
|---|---|---|
| kind | string enum | Curve: spring |
| value | expr | The expression or state ref whose change triggers the animation. |
| duration | number (sec) | Animation duration in seconds. |
| bounce | number 0–1 | Spring bounce amount (spring animations only). |
| blendDuration | number (sec) | Duration for blending between animation states. |
| repeater | object | Repeat: { “count”: number, “repeatForever”: bool, “autoreverses”: bool }. |
7.11 style.modal
Section titled “7.11 style.modal”Modal overlays are configured in style rather than via navigation actions. All modal types require an isPresented binding to a state boolean.
A style.modal block declares one or more modal types, keyed by type name (each type at most once). Every declared modal is attached independently, with its own isPresented binding — so a single component can present, e.g., both an alert and a sheet at once, mirroring SwiftUI’s stackable .alert(…).sheet(…) modifiers. When several are declared they attach in a fixed order: alert → sheet → popover → fullScreenCover.
| Modal type | Required properties | Optional |
|---|---|---|
| alert | title, isPresented | message, actions (array of button components) |
| popover | isPresented, content (component) | — |
| sheet | isPresented, content (component) | — |
| fullScreenCover | isPresented, content (component) | — |
"style": {"modal": {"alert": {"title": "Delete item?","message": "This cannot be undone.","isPresented": "${showDeleteAlert}","actions": [{ "id": "btn_cancel", "type": "button", "context": { "_label": "Cancel" } },{ "id": "btn_confirm", "type": "button", "context": { "_label": "Delete" },"events": { "onTap": [{ "state": { "id": "dismiss","input": { "showDeleteAlert": false } } }] } }]}}}A single component may carry several modals — each its own key, each with an independent isPresented:
"style": {"modal": {"alert": {"title": "Delete item?","isPresented": "${showDeleteAlert}","actions": [{ "id": "btn_confirm", "type": "button", "context": { "_label": "Delete" } }]},"sheet": {"isPresented": "${showDetails}","content": { "id": "details_panel", "type": "vstack", "children": [] }}}}7.12 style.text
Section titled “7.12 style.text”Applied to text components to control typographic presentation.
| Property | Type / Values | Description |
|---|---|---|
| multilineTextAlignment | string enum | Text alignment: leading |
| lineLimit | integer | Maximum number of lines. Absent means unlimited. |
| lineSpacing | number | Extra vertical space between lines in points. |
| truncationMode | string enum | Truncation position: head |
| minimumScaleFactor | number 0–1 | Minimum scale factor for automatic font shrinking. |
| bold | boolean | Applies bold weight to the text font. |
| italic | boolean | Applies italic style to the text font. |
| textCase | string enum | Transforms text casing: uppercase (or upper) |
7.13 style.textField
Section titled “7.13 style.textField”Applied to textfield components to control input appearance.
| Property | Type / Values | Description |
|---|---|---|
| standard | string enum | Input field style: automatic |
| keyboardType | string enum | Keyboard layout: default |
| autocapitalization | string enum | Capitalization: sentences |
| submitLabel | string enum | Return key label: done |
| autocorrectionDisabled | boolean | When true, disables autocorrection for this field. |
7.14 style.datePicker
Section titled “7.14 style.datePicker”| Property | Type / Values | Description |
|---|---|---|
| preset | string enum | Picker display style: compact |
| preset | Description |
|---|---|
| compact | Compact inline display with expandable calendar popover. |
| graphical | Full calendar grid displayed inline. |
| wheel | Scrolling drum-roll wheel picker. |
| automatic | Platform-chosen default based on context. |
7.15 style.shadow
Section titled “7.15 style.shadow”| Property | Type | Description |
|---|---|---|
| color | color value | Shadow color. Default: black with reduced opacity. |
| radius | number | Shadow blur radius in points. |
| x | number | Horizontal shadow offset. Positive shifts right. |
| y | number | Vertical shadow offset. Positive shifts down. |
| outer | boolean | When true, prevents shadow from showing through transparent areas. |
7.16 style.scroll
Section titled “7.16 style.scroll”Applied to scroll and list components to control scrolling behavior.
| Property | Type / Values | Description |
|---|---|---|
| anchor | string or object | Scroll anchor point. Values: top |
| scrollDisabled | boolean | When true, disables scrolling interaction. |
| bounce | boolean | Controls bounce behavior. |
| paging | boolean | When true, enables paged scrolling (one full page per swipe). |
| dismissesKeyboard | string | Keyboard dismissal behaviour when the user scrolls. Values: automatic | interactively | immediately | never. When unset, platform default stands. |
ℹ Keyboard dismissal. Numeric keyboards (
decimalPad,numberPad,phonePad) have no Return key, so forms containing them should setstyle.scroll.dismissesKeyboardon an enclosing scroll."immediately"dismisses on any scroll;"interactively"follows the user’s drag. Alphanumeric keyboards additionally support the Return key (seestyle.textField.submitLabel).
7.17 style.swipe
Section titled “7.17 style.swipe”Applied to list rows or any component to add swipe-to-reveal actions.
| Property | Type | Description |
|---|---|---|
| leading | SwipeManifest | Swipe actions revealed from the leading (left) edge. |
| trailing | SwipeManifest | Swipe actions revealed from the trailing (right) edge. |
SwipeManifest structure:
| Field | Type | Description |
|---|---|---|
| content | component | The component rendered as the swipe action button. |
| allowsFullSwipe | boolean | When true, a full swipe triggers the first action automatically. Default: false. |
"style": {"swipe": {"trailing": {"content": {"id": "delete_btn", "type": "button","context": { "_label": "Delete" },"style": { "common": { "foreground": { "color": "white" },"background": { "color": "red" } } },"events": { "onTap": [{ "state": { "id": "del_act","input": { "deleteId": "@{item.id}" } } }] }},"allowsFullSwipe": true}}}7.18 style.section
Section titled “7.18 style.section”Applied to section components inside a form or list to override platform-default row presentation.
| Property | Type / Values | Description |
|---|---|---|
| listRowBackground | color value | Background color applied to every row in the section. “clear” removes the default background entirely. |
| listRowInsets | string or object | Inset override for every row. “zero” removes the default insets. Object form: { top, bottom, leading, trailing }. |
"style": {"section": {"listRowBackground": "clear","listRowInsets": "zero"}}7.19 style.map
Section titled “7.19 style.map”Applied to map components to control visual presentation. When omitted, the map renders with the standard style.
| Property | Type / Values | Description |
|---|---|---|
| kind | string enum | Map presentation style. One of: standard (default), hybrid, imagery. |
| kind value | Description | |
| standard | Vector road map with labels. Default when style.map is absent. | |
| hybrid | Satellite imagery overlaid with roads and labels. | |
| imagery | Satellite imagery only, no roads or labels. |
"style": {"map": {"kind": "hybrid"}}7.20 style.picker
Section titled “7.20 style.picker”Applied to picker components to control the presentation style. When omitted, the platform’s automatic default is used.
| Property | Type / Values | Description |
|---|---|---|
| picker | string enum | Picker presentation style. One of: segmented, menu, wheel, inline, automatic (default). |
| Value | Description |
|---|---|
| segmented | Horizontal segmented control. Best for a small number of short options (2–5). |
| menu | Compact drop-down menu. Suitable for longer option lists. |
| wheel | Scrolling drum-roll wheel. Familiar for date-style or multi-column selection. |
| inline | Expanded inline picker embedded directly in the layout. |
| automatic | Platform-chosen default based on context. Applied when style.picker is absent. |
"style": { "picker": "menu" }"style": { "picker": "segmented" }"style": { "picker": "wheel" }7.21 style.video
Section titled “7.21 style.video”Applied to video and media components to control AVKit presentation. Consumed directly by the renderer; not applied as a SwiftUI view modifier.
| Property | Type / Values | Description |
|---|---|---|
| controls | bool | Show or hide native AVKit playback controls. Default: true. |
| gravity | string enum | Video fill / fit behaviour inside the component frame. Default: resizeAspect. |
| gravity value | Description |
|---|---|
| resizeAspect | Letterbox / pillarbox to fit frame. Preserves aspect ratio (default). |
| resizeAspectFill | Crop to fill frame. Preserves aspect ratio; may clip edges. |
| resize | Stretch to fill frame. Distorts aspect ratio. |
"style": { "video": { "controls": false, "gravity": "resizeAspectFill" }}7.22 style.pdf
Section titled “7.22 style.pdf”Applied to pdf and media components to control PDFView layout. Consumed directly by the renderer; not applied as a SwiftUI view modifier.
| Property | Type / Values | Description |
|---|---|---|
| displayMode | string enum | Page layout mode. Default: singlePage. |
| displayDirection | string enum | Scroll axis. Default: vertical. |
| autoScales | bool | Scale each page to fit the view width automatically. Default: true. |
| showPageNumbers | bool | Display a page-number overlay. Default: false. |
| displayMode value | Description |
|---|---|
| singlePage | One page at a time (default). |
| singlePageContinuous | Continuous single-column scroll. |
| twoUp | Two pages side-by-side. |
| twoUpContinuous | Continuous two-column scroll. |
| displayDirection | Description |
|---|---|
| vertical | Scroll top to bottom (default). |
| horizontal | Scroll left to right (page-turn style). |
"style": { "pdf": { "displayMode": "singlePageContinuous", "displayDirection": "vertical", "autoScales": true, "showPageNumbers": true }}7.23 style.grid
Section titled “7.23 style.grid”Applied to grid components to configure track sizing and pinned section views. Consumed directly by the renderer. lazyVGrid uses columns; lazyHGrid uses rows; plain grid ignores both (SwiftUI Grid manages its own layout).
| Property | Type | Description |
|---|---|---|
| columns | array of items | Column track descriptors for lazyVGrid. One descriptor per track. |
| rows | array of items | Row track descriptors for lazyHGrid. One descriptor per track. |
| pinnedViews | string enum | Sections to pin while scrolling. Default: none. |
Grid item object
| Field | Type | Required for kind | Description |
|---|---|---|---|
| kind | string | Always | Track sizing algorithm: fixed, flexible, or adaptive. |
| size | number | fixed only | Exact track size in points. |
| minimum | number | adaptive required; flexible optional | Minimum track size in points. Default: 10. |
| maximum | number | Optional | Maximum track size in points. Default: infinity (no limit). |
| spacing | number | Optional | Spacing between items in this track. Default: platform default. |
| alignment | string | Optional | Per-item alignment within the track. Accepts any alignment value from §7 alignment table. |
| kind value | Sizing behaviour |
|---|---|
| fixed | Track is exactly size points wide/tall. size is required. |
| flexible | Track grows/shrinks between minimum and maximum. |
| adaptive | Renderer fits as many minimum-sized items as possible per track. |
| pinnedViews value | Description |
|---|---|
| sectionHeaders | Pin section header views while scrolling. |
| sectionFooters | Pin section footer views while scrolling. |
| all | Pin both headers and footers. |
"style": { "grid": { "columns": [ { "kind": "adaptive", "minimum": 80 }, { "kind": "flexible" }, { "kind": "fixed", "size": 120 } ], "pinnedViews": "sectionHeaders" }}7.24 style.splitView
Section titled “7.24 style.splitView”Applied to splitview components to configure column layout. Consumed directly by the renderer; not applied as a SwiftUI modifier.
| Property | Type | Required | Description |
|---|---|---|---|
| preferred | string | Optional | Split view layout style: "automatic" (default) | "balanced" | "prominentDetail". |
| visibility | string | Optional | Initial column visibility: "automatic" (default) | "all" | "detailOnly". |
| sidebarWidth | object | Optional | Sidebar column width constraints (see below). Omit to use system defaults. |
sidebarWidth object
| Field | Type | Required | Description |
|---|---|---|---|
| min | number | Optional | Minimum sidebar width in points. |
| ideal | number | Optional | Preferred sidebar width in points. |
| max | number | Optional | Maximum sidebar width in points. |
| preferred value | Behaviour |
|---|---|
| automatic | System default. Matches balanced on most iPads. |
| balanced | Sidebar and detail share roughly equal space. |
| prominentDetail | Detail column is prominent; sidebar can be collapsed to a thin strip. |
| visibility value | Columns shown on appearance |
|---|---|
| automatic | System decides based on available width. |
| all | All columns visible on appearance (sidebar + detail, or sidebar + content + detail). |
| detailOnly | Only the detail column is visible on appearance; sidebar is hidden. |
"style": { "splitView": { "preferred": "balanced", "visibility": "all", "sidebarWidth": { "min": 200, "ideal": 260, "max": 320 } }}7.25 style.accessibility
Section titled “7.25 style.accessibility”Accessibility properties for assistive technologies (VoiceOver, Switch Control). Applied after all visual styles. All properties are optional — omit the entire accessibility domain when a component’s built-in semantics are sufficient.
| Property | Type | Description |
|---|---|---|
| label | string / expr | Short description read by VoiceOver. Overrides the component’s default label. |
| hint | string / expr | Additional context describing the result of activating the element (e.g. “Double tap to save your changes”). |
| value | string / expr | Current value for stateful components (sliders, progress). Supports expressions for dynamic updates. |
| hidden | bool / expr | When true, the component is hidden from the accessibility tree. Use for decorative elements. |
| traits | string | Semantic role(s). Comma-separated. See trait values below. |
| identifier | string / expr | Stable identifier for UI testing frameworks. Not read by VoiceOver. |
Supported trait values
| Value | Meaning |
|---|---|
button | Element behaves as a button. |
header | Element is a section header. |
image | Element is an image. |
link | Element is a hyperlink. |
selected | Element is currently selected. |
searchField | Element is a search field. |
startsMediaSession | Activating this element starts media playback. |
updatesFrequently | Element’s value changes frequently (e.g. a timer). |
isModal | Element is part of a modal interface. |
Multiple traits: "traits": "button, header".
When to use
- Interactive elements without visible text — icon-only buttons MUST have a
label. - Decorative elements — dividers, background images, and debug views SHOULD set
"hidden": true. - Dynamic state — progress bars, sliders, counters SHOULD provide a
valueexpression that updates as state changes. - Sections — section headers SHOULD set
"traits": "header"for proper navigation.
Example
{ "id": "save_btn", "type": "button", "context": { "_label": "", "_image": "sf://checkmark.circle.fill" }, "style": { "accessibility": { "label": "Save", "hint": "Saves your changes", "traits": "button" } }}Dynamic value example:
"style": { "accessibility": { "label": "Download progress", "value": "{{ ${progress} * 100 + '% complete' }}", "traits": "updatesFrequently" }}7.26 style.tab
Section titled “7.26 style.tab”Tab bar appearance for tab components. All properties are optional color values.
| Property | Type | Description |
|---|---|---|
| selectedTint | color value | Color of the selected tab bar item. |
| unselectedTint | color value | Color of unselected tab bar items. |
| barBackground | color value | Tab bar background color. |
"style": { "tab": { "selectedTint": "blue", "unselectedTint": "#AAAAAA", "barBackground": "black" }}7.27 style.common.glass (iOS 26+)
Section titled “7.27 style.common.glass (iOS 26+)”The glass property in style.common applies the iOS 26 liquid glass effect to a component. On older OS versions, the runtime falls back to a thin material background.
| Value | Effect |
|---|---|
regular | Default glass. Medium transparency, adapts to any content. Suitable for most controls. |
clear | High transparency. Best on media-rich or vibrant backgrounds. |
identity | No visual effect. Use for conditional toggling via expressions. |
Glass uses the component’s cornerRadius for shape. If cornerRadius is not set, defaults to 16 points.
"style": { "common": { "glass": "regular", "cornerRadius": 20 }}Dynamic toggling:
"glass": "{{ ${isGlassEnabled} ? 'regular' : 'identity' }}"Backward compatibility: On iOS 18 and earlier, glass falls back to .ultraThinMaterial with the same corner radius — the layout remains identical, only the visual effect differs.
Design guidance: Glass is best for controls floating over content (navigation bars, floating buttons, overlays). Avoid applying glass to large content areas or list rows.