UI Element Catalog
Every one of the 48 native UI elements accepted by Atlas and exported in UI_TYPES is documented here. Atlas supplies typography, spacing, accessibility sizing, and appearance. Properties affect only the components that implement them; arbitrary CSS or Swift is not supported.
Generated from the SDK component guide and checked against the native validator and UI_TYPES.
Using these examples
Import ui from atlas-bot-sdk/experiences. Each example is an element fragment: put it inside your experience UI. Merge any accompanying properties into ExperienceDefinition.properties. Schema defaults are strings, including JSON, numbers, and booleans. Asset examples need a real bundled file at the shown path. Declare every action tool and required permission in the pack grants. ScreenHeader/BottomBar are host-rendered chrome; Page/Sheet/Dialog are hidden declarations until opened. All other elements render as body content.
All elements support an optional id and visible_when condition. Button actions use action: { tool, args } or workflow; enabled_when controls action availability where implemented. Conditions support scope, equals, not_equals, contains, and exists. Use #/properties/name for schema bindings and {{name}} for text interpolation. Chart/graph field selectors refer to record keys, such as label or from, rather than schema pointers. Native device inputs may need operating-system permissions; granting a tool does not bypass those prompts.
import { ui } from "atlas-bot-sdk/experiences";
Element index
Layout
VerticalLayout · HorizontalLayout · Group · Card · Panel · List · Grid · Carousel · StepperCarousel
Text and status
Text · Markdown · Display · Badge · Metric · Divider · Hero · StatusBanner · Progress · SummaryRow · KeyValueGrid
Inputs
Control · Toggle · Picker · Slider · Stepper · SearchField · FilterBar
Actions
Button · ButtonGrid · ActionBar · BottomBar
Navigation
ScreenHeader · Page · Sheet · Dialog
Media
Image · ImageCard · ItemRow · WebView · DocumentPreview · MapView
Device inputs
FilePicker · ScannerButton · ContactPickerButton
Data
Chart · Graph · ModelCard · ModelList
VerticalLayout
Stack child elements vertically.
Properties: elements: child elements; title/subtitle/text: supported by Group and Card; buttons: grouped actions.
Atlas owns spacing and appearance. HorizontalLayout does not automatically become a grid on a narrow screen.
ui("VerticalLayout", {
"elements": [
{
"type": "Text",
"text": "Delivery details"
}
]
})
HorizontalLayout
Place a small number of children side by side.
Properties: elements: child elements; title/subtitle/text: supported by Group and Card; buttons: grouped actions.
Atlas owns spacing and appearance. HorizontalLayout does not automatically become a grid on a narrow screen.
ui("HorizontalLayout", {
"elements": [
{
"type": "Text",
"text": "Delivery details"
}
]
})
Group
Group related controls; native forms use a section, experience screens use a panel.
Properties: elements: child elements; title/subtitle/text: supported by Group and Card; buttons: grouped actions.
Atlas owns spacing and appearance. HorizontalLayout does not automatically become a grid on a narrow screen.
ui("Group", {
"elements": [
{
"type": "Text",
"text": "Delivery details"
}
]
})
Card
Group a title, supporting copy, child content, and actions.
Properties: elements: child elements; title/subtitle/text: supported by Group and Card; buttons: grouped actions.
Atlas owns spacing and appearance. HorizontalLayout does not automatically become a grid on a narrow screen.
ui("Card", {
"elements": [
{
"type": "Text",
"text": "Delivery details"
}
]
})
Panel
A content container with optional status, navigation, route, or profile presentation.
Properties: title, headline, subtitle, caption, text, footer, icon, elements, buttons; action/workflow for navigation; image_scope and secondary_scope for profile artwork.
Styles: plain, primary, result, warning, quiet; experience-specific inline, navigation, navigation-row, profile, arrival; route and route-plain render ordered child title/text stops. Navigation cards use a single action; avoid nested action controls. Profile supports avatar/artwork; arrival uses headline/subtitle and caption/text.
ui("Panel", {
"title": "Your order",
"style": "quiet",
"elements": [
{
"type": "SummaryRow",
"title": "Total",
"text": "$18"
}
]
})
List
Render explicit child rows or collection records.
Properties: elements or items: child elements; columns: Grid column count; collection_scope: List/Grid collection result; selected_index_scope: StepperCarousel index.
Use a JSON collection-query result for collection_scope, not a plain array of arbitrary UI elements. Carousel and StepperCarousel use explicit children.
ui("List", {
"elements": [
{
"type": "Text",
"text": "First item"
},
{
"type": "Text",
"text": "Second item"
}
]
})
Grid
Arrange explicit children or collection records in flexible columns.
Properties: elements or items: child elements; columns: Grid column count; collection_scope: List/Grid collection result; selected_index_scope: StepperCarousel index.
Use a JSON collection-query result for collection_scope, not a plain array of arbitrary UI elements. Carousel and StepperCarousel use explicit children.
ui("Grid", {
"elements": [
{
"type": "Text",
"text": "First item"
},
{
"type": "Text",
"text": "Second item"
}
],
"columns": 2
})
Carousel
Show explicit children in a horizontally scrolling row.
Properties: elements or items: child elements; columns: Grid column count; collection_scope: List/Grid collection result; selected_index_scope: StepperCarousel index.
Use a JSON collection-query result for collection_scope, not a plain array of arbitrary UI elements. Carousel and StepperCarousel use explicit children.
ui("Carousel", {
"elements": [
{
"type": "Text",
"text": "First item"
},
{
"type": "Text",
"text": "Second item"
}
]
})
StepperCarousel
Show one explicit child at a time with previous/next controls.
Properties: elements or items: child elements; columns: Grid column count; collection_scope: List/Grid collection result; selected_index_scope: StepperCarousel index.
Use a JSON collection-query result for collection_scope, not a plain array of arbitrary UI elements. Carousel and StepperCarousel use explicit children.
ui("StepperCarousel", {
"elements": [
{
"type": "Text",
"text": "First item"
},
{
"type": "Text",
"text": "Second item"
}
],
"selected_index_scope": "#/properties/slide"
})
Add to ExperienceDefinition.properties:
{
"slide": {
"type": "number",
"default": "0"
}
}
Text
Display a text block.
Properties: text: literal or interpolated copy; scope: bound value; title: label; subtitle: supporting copy where rendered. Metric supports secondary_scope.
Text supports style: headline or secondary. Markdown uses native text formatting, not arbitrary HTML. Metric can bind secondary_scope to a comparison value.
ui("Text", {
"text": "Order ready"
})
Markdown
Display formatted text through the native Markdown renderer.
Properties: text: literal or interpolated copy; scope: bound value; title: label; subtitle: supporting copy where rendered. Metric supports secondary_scope.
Text supports style: headline or secondary. Markdown uses native text formatting, not arbitrary HTML. Metric can bind secondary_scope to a comparison value.
ui("Markdown", {
"text": "Order ready"
})
Display
Display a bound or literal value, optionally paired with a label.
Properties: text: literal or interpolated copy; scope: bound value; title: label; subtitle: supporting copy where rendered. Metric supports secondary_scope.
Text supports style: headline or secondary. Markdown uses native text formatting, not arbitrary HTML. Metric can bind secondary_scope to a comparison value.
ui("Display", {
"text": "Order ready"
})
Badge
Display a compact accent-colored text badge.
Properties: text: literal or interpolated copy; scope: bound value; title: label; subtitle: supporting copy where rendered. Metric supports secondary_scope.
Text supports style: headline or secondary. Markdown uses native text formatting, not arbitrary HTML. Metric can bind secondary_scope to a comparison value.
ui("Badge", {
"text": "Order ready"
})
Metric
Display a prominent value with optional secondary value.
Properties: text: literal or interpolated copy; scope: bound value; title: label; subtitle: supporting copy where rendered. Metric supports secondary_scope.
Text supports style: headline or secondary. Markdown uses native text formatting, not arbitrary HTML. Metric can bind secondary_scope to a comparison value.
ui("Metric", {
"text": "$18"
})
Divider
Separate adjacent content with a native rule.
Properties: No element-specific properties.
ui("Divider", {})
Hero
Introduce a screen with prominent text, an optional SF Symbol, and bullets.
Properties: title/headline, subtitle, caption, text, icon, bullets; style.
Default Hero renders supporting text and bullets. style: compact renders only the heading and subtitle with smaller typography. Use Image or ImageCard for photos and ActionBar for actions.
ui("Hero", {
"headline": "Dinner, delivered",
"subtitle": "Browse local favorites",
"style": "compact"
})
StatusBanner
Display a status message and optional bound state.
Properties: title, text, state_scope (or scope), style.
Styles: result for success, warning for attention; default uses the informational appearance.
ui("StatusBanner", {
"title": "Order confirmed",
"text": "Your meal is being prepared.",
"style": "result"
})
Progress
Display numeric progress toward a maximum.
Properties: scope: numeric value; max: positive maximum (default 100); text: label.
Set max greater than zero. The displayed fraction is clamped to 0–1.
ui("Progress", {
"scope": "#/properties/progress",
"max": 100,
"text": "Preparing order"
})
Add to ExperienceDefinition.properties:
{
"progress": {
"type": "number",
"default": "40"
}
}
SummaryRow
Display a title and value, or an experience section heading.
Properties: title, text, subtitle, caption, style, action/workflow.
Use style: section for a heading with trailing action/value. Actions are subject to the pack grants.
ui("SummaryRow", {
"title": "Delivery",
"text": "$2.00"
})
KeyValueGrid
Display labeled values in a grid.
Properties: items: labeled value elements; columns: column count; collection_scope: optional collection result.
When using a collection, this element reads the first record; explicit items customize its displayed fields.
ui("KeyValueGrid", {
"columns": 2,
"items": [
{
"type": "Display",
"title": "ETA",
"text": "20 min"
},
{
"type": "Display",
"title": "Fee",
"text": "$2"
}
]
})
Control
Edit a schema-bound value as text.
Properties: scope: required schema binding; title: optional label override. Schema readOnly produces a value display.
Choose Toggle, Picker, Slider, or Stepper explicitly for those native controls. Declaring a numeric schema does not turn Control into a slider.
ui("Control", {
"scope": "#/properties/address"
})
Add to ExperienceDefinition.properties:
{
"address": {
"type": "string",
"default": "123 Market Street",
"title": "Delivery address"
}
}
Toggle
Edit a boolean value with a native switch.
Properties: scope: boolean property; title: label.
Form state stores boolean values as strings.
ui("Toggle", {
"title": "Leave at door",
"scope": "#/properties/leaveAtDoor"
})
Add to ExperienceDefinition.properties:
{
"leaveAtDoor": {
"type": "boolean",
"default": "true"
}
}
Picker
Choose exactly one option.
Properties: scope, options, style, search_scope. Each option has title/value and may add subtitle, icon, trailing, image, caption.
Styles: native default, cards, rows, compact, rating. Rating uses ordered star options. Cards/rows/compact support richer option details and search_scope filtering; image references may use asset: paths.
ui("Picker", {
"title": "Ride type",
"scope": "#/properties/ride",
"style": "compact",
"options": [
{
"title": "Standard",
"value": "standard",
"trailing": "$18"
},
{
"title": "Comfort",
"value": "comfort",
"trailing": "$24"
}
]
})
Add to ExperienceDefinition.properties:
{
"ride": {
"type": "string",
"default": "standard"
}
}
Slider
Edit a numeric value within a range.
Properties: scope, min (default 0), max (default 100), step (default 1); Stepper text labels the value.
Use min ≤ max and a positive step.
ui("Slider", {
"scope": "#/properties/quantity",
"min": 1,
"max": 10,
"step": 1,
"text": "Quantity {{quantity}}"
})
Add to ExperienceDefinition.properties:
{
"quantity": {
"type": "number",
"default": "1"
}
}
Stepper
Edit a numeric value within a range.
Properties: scope, min (default 0), max (default 100), step (default 1); Stepper text labels the value.
Use min ≤ max and a positive step.
ui("Stepper", {
"scope": "#/properties/quantity",
"min": 1,
"max": 10,
"step": 1,
"text": "Quantity {{quantity}}"
})
Add to ExperienceDefinition.properties:
{
"quantity": {
"type": "number",
"default": "1"
}
}
SearchField
Edit a search query with a native clear button.
Properties: scope: query binding; title: placeholder.
Pair the query with search_scope on searchable content. The field itself does not fetch or filter a backend.
ui("SearchField", {
"title": "Search restaurants",
"scope": "#/properties/query"
})
Add to ExperienceDefinition.properties:
{
"query": {
"type": "string",
"default": ""
}
}
FilterBar
Show evenly spaced category choices and update one selected value.
Properties: scope: selected category; options: title/value plus optional icon.
Connect the value to filter_scope/filter_values or conditional content; choosing a category does not query a server.
ui("FilterBar", {
"scope": "#/properties/category",
"options": [
{
"title": "All",
"value": "all"
},
{
"title": "Pizza",
"value": "pizza"
}
]
})
Add to ExperienceDefinition.properties:
{
"category": {
"type": "string",
"default": "all"
}
}
Button
Run an experience action or workflow when tapped.
Properties: title, icon, action or workflow, primary, enabled_when, visible_when.
This is a UIAction inside the experience. Existing chat buttons use ExperienceButtonAction, a different payload. Grant ui.toast for this example.
ui("Button", {
"title": "Continue",
"action": {
"tool": "ui.toast",
"args": {
"message": "Demo action"
}
}
})
ButtonGrid
Show actions in a grid.
Properties: buttons: action definitions; columns: ButtonGrid column count. BottomBar also supports style, text, footer.
Grant the tools referenced by the buttons. BottomBar is extracted by the experience screen host; use ActionBar in sheets. BottomBar style: midnight provides a neutral primary action.
ui("ButtonGrid", {
"buttons": [
{
"title": "Continue",
"action": {
"tool": "ui.toast",
"args": {
"message": "Demo action"
}
}
}
],
"columns": 2
})
ActionBar
Show a group of actions inside content.
Properties: buttons: action definitions; columns: ButtonGrid column count. BottomBar also supports style, text, footer.
Grant the tools referenced by the buttons. BottomBar is extracted by the experience screen host; use ActionBar in sheets. BottomBar style: midnight provides a neutral primary action.
ui("ActionBar", {
"buttons": [
{
"title": "Continue",
"action": {
"tool": "ui.toast",
"args": {
"message": "Demo action"
}
}
}
]
})
BottomBar
Reserve the bottom safe area for experience actions.
Properties: buttons: action definitions; columns: ButtonGrid column count. BottomBar also supports style, text, footer.
Grant the tools referenced by the buttons. BottomBar is extracted by the experience screen host; use ActionBar in sheets. BottomBar style: midnight provides a neutral primary action.
ui("BottomBar", {
"buttons": [
{
"title": "Continue",
"action": {
"tool": "ui.toast",
"args": {
"message": "Demo action"
}
}
}
]
})
ScreenHeader
Configure the native experience toolbar title, subtitle, caption, and actions.
Properties: title, subtitle, caption, action/workflow, buttons, style.
Only the experience screen host renders this element; it is not an ordinary body row. Use screen() or page() to place it. Native glass icon buttons, Back/Close, and overflow are app-owned. style: compact reduces spacing.
ui("ScreenHeader", {
"title": "{{address}}",
"caption": "Deliver to",
"buttons": [
{
"title": "Basket",
"icon": "basket",
"action": {
"tool": "ui.toast",
"args": {
"message": "Basket"
}
}
}
]
})
Add to ExperienceDefinition.properties:
{
"address": {
"type": "string",
"default": "123 Market Street"
}
}
Page
Declare a separate screen in the navigation flow.
Properties: id: navigation target; title; elements: body; buttons: actions.
Declarations are hidden until opened. Use ui.open_page with args.target matching id and grant both open/close tools. Pages share form state and support push/replace/root navigation. Sheets and dialogs support child content and actions; ScreenHeader/BottomBar belong to pages. Page/Sheet may also be opened directly from a chat button.
ui("Page", {
"id": "page-details",
"title": "Details",
"elements": [
{
"type": "Text",
"text": "Delivery details"
}
],
"buttons": [
{
"title": "Close",
"action": {
"tool": "ui.close_page"
}
}
]
})
Sheet
Declare a native bottom sheet for focused edits.
Properties: id: navigation target; title; elements: body; buttons: actions.
Declarations are hidden until opened. Use ui.open_sheet with args.target matching id and grant both open/close tools. Pages share form state and support push/replace/root navigation. Sheets and dialogs support child content and actions; ScreenHeader/BottomBar belong to pages. Page/Sheet may also be opened directly from a chat button.
ui("Sheet", {
"id": "sheet-details",
"title": "Details",
"elements": [
{
"type": "Text",
"text": "Delivery details"
}
],
"buttons": [
{
"title": "Close",
"action": {
"tool": "ui.close_sheet"
}
}
]
})
Dialog
Declare a confirmation or richer modal dialog.
Properties: id: navigation target; title; elements: body; buttons: actions.
Declarations are hidden until opened. Use ui.open_dialog with args.target matching id and grant both open/close tools. Pages share form state and support push/replace/root navigation. Sheets and dialogs support child content and actions; ScreenHeader/BottomBar belong to pages. Page/Sheet may also be opened directly from a chat button.
ui("Dialog", {
"id": "dialog-details",
"title": "Details",
"elements": [
{
"type": "Text",
"text": "Delivery details"
}
],
"buttons": [
{
"title": "Close",
"action": {
"tool": "ui.close_dialog"
}
}
]
})
Image
Display a bound image URL or installed-pack asset.
Properties: url_scope, image_scope, or scope: source binding; title: image description; text: empty fallback.
Use a real HTTPS image or bundle-relative asset: reference. Image is not a file picker.
ui("Image", {
"title": "Meal photo",
"image_scope": "#/properties/photo"
})
Add to ExperienceDefinition.properties:
{
"photo": {
"type": "string",
"default": "asset:assets/meal.jpg"
}
}
ImageCard
Display a tappable photo card with text and optional overlay actions.
Properties: image_scope, title, subtitle, caption, action/workflow, buttons.
caption is displayed alongside a star. The card action and overlay buttons are separate tap targets. Supply action/workflow to make the card navigate.
ui("ImageCard", {
"title": "Olive Kitchen",
"subtitle": "Mediterranean · 20–30 min",
"caption": "4.8",
"image_scope": "#/properties/photo"
})
Add to ExperienceDefinition.properties:
{
"photo": {
"type": "string",
"default": "asset:assets/meal.jpg"
}
}
ItemRow
Display a menu or basket item with photo, details, and optional quantity actions.
Properties: title, subtitle, text, image_scope, scope: quantity; buttons: quantity actions; style.
style: basket uses a compact leading photo. The default has a trailing photo. Quantity changes require actions/workflows in buttons; this element does not compute prices automatically.
ui("ItemRow", {
"title": "Chicken bowl",
"subtitle": "Roasted vegetables",
"text": "$14",
"image_scope": "#/properties/photo",
"style": "basket"
})
Add to ExperienceDefinition.properties:
{
"photo": {
"type": "string",
"default": "asset:assets/meal.jpg"
}
}
WebView
Embed a web preview in the experience.
Properties: url_scope (or scope): http/https URL; max: height; text: unavailable message.
Web content supplies its own design; it does not inherit native Atlas controls.
ui("WebView", {
"title": "Help",
"url_scope": "#/properties/website",
"max": 320
})
Add to ExperienceDefinition.properties:
{
"website": {
"type": "string",
"default": "https://example.com"
}
}
DocumentPreview
Preview a document through the native QuickLook surface.
Properties: url_scope (or scope): document URL/file binding; max: height.
Provide a supported, accessible document reference. An empty binding shows the unavailable state.
ui("DocumentPreview", {
"title": "Receipt",
"url_scope": "#/properties/document",
"max": 320
})
Add to ExperienceDefinition.properties:
{
"document": {
"type": "file",
"default": ""
}
}
FilePicker
Choose a file with the system importer and write its binding.
Properties: scope: file property; title: label. Schema allowed_types filters file types.
Uses the registered workflow.file.pick native importer. The selected local file reference is written to scope; uploading or sharing it requires a separate explicit action.
ui("FilePicker", {
"title": "Attach receipt",
"scope": "#/properties/document"
})
Add to ExperienceDefinition.properties:
{
"document": {
"type": "file",
"default": "",
"allowed_types": [
"pdf",
"image"
]
}
}
ScannerButton
Open the native code scanner and write the result to a binding.
Properties: title, icon, scope: JSON result binding.
Default action: scanner.scan_code. Grant scanner.scan_code and camera permission. This scans codes; it is not arbitrary document OCR. An explicit action may override the default.
ui("ScannerButton", {
"title": "Scan code",
"scope": "#/properties/scan"
})
Add to ExperienceDefinition.properties:
{
"scan": {
"type": "json",
"default": ""
}
}
ContactPickerButton
Open the native contact picker and write its result to a binding.
Properties: title, icon, scope: JSON result binding.
Default action: contacts.pick_contact. Grant contacts.pick_contact and contacts permission. Selection writes JSON and does not send a message. An explicit action may override the default.
ui("ContactPickerButton", {
"title": "Choose contact",
"scope": "#/properties/contact"
})
Add to ExperienceDefinition.properties:
{
"contact": {
"type": "json",
"default": ""
}
}
MapView
Render supplied coordinates and optional route points in a native map.
Properties: scope: coordinate JSON; x_scope/y_scope: longitude/latitude alternatives; items_scope: route JSON; selected_index_scope: route selector; max: height; style.
style: stage supplies a map-led screen background under native chrome. Routes use [longitude, latitude] pairs, at most 1,000 points; a keyed object supports route selection. This element does not request GPS or calculate a route.
ui("MapView", {
"title": "Pickup",
"scope": "#/properties/location",
"style": "stage",
"max": 260
})
Add to ExperienceDefinition.properties:
{
"location": {
"type": "json",
"default": "{\"latitude\": 37.7857, \"longitude\": -122.4011}"
}
}
Chart
Render a bar, line, area, pie, or donut chart.
Properties: items: explicit numeric value elements; items_scope/collection_scope/scope: JSON data; label_scope/x_scope and value_scope/y_scope: record field names; max: numeric scale.
Styles: bar (default), line, area, pie, donut. In a JSON dataset, label_scope/value_scope are record keys, not schema pointers. Values must be numeric.
ui("Chart", {
"title": "Orders",
"style": "bar",
"items": [
{
"type": "Display",
"title": "Mon",
"text": "12"
},
{
"type": "Display",
"title": "Tue",
"text": "18"
}
]
})
Graph
Render a graph of supplied nodes and edges.
Properties: items: explicit labeled nodes; items_scope/collection_scope/scope: JSON data; label_scope, from_scope, to_scope: record field names.
Without explicit edges the renderer connects nodes sequentially. For edge data provide records with from/to keys, or name those keys with from_scope/to_scope. This is data visualization, not a workflow editor.
ui("Graph", {
"title": "Order journey",
"items": [
{
"type": "Text",
"id": "received",
"title": "Received"
},
{
"type": "Text",
"id": "delivered",
"title": "Delivered"
}
]
})
ModelCard
Render the first object as a card.
Properties: items_scope/collection_scope/scope: model data; title, subtitle; elements/items: optional child template.
JSON may contain an object or array of objects. Without a child template, fields display as key/value pairs. Templates can interpolate object keys. Empty data uses a native empty state.
ui("ModelCard", {
"title": "Orders",
"items_scope": "#/properties/orders"
})
Add to ExperienceDefinition.properties:
{
"orders": {
"type": "json",
"default": "[{\"id\": \"demo-1\", \"title\": \"Order #1\", \"status\": \"Preparing\"}]"
}
}
ModelList
Render a card for each data object.
Properties: items_scope/collection_scope/scope: model data; title, subtitle; elements/items: optional child template.
JSON may contain an object or array of objects. Without a child template, fields display as key/value pairs. Templates can interpolate object keys. Empty data uses a native empty state.
ui("ModelList", {
"title": "Orders",
"items_scope": "#/properties/orders"
})
Add to ExperienceDefinition.properties:
{
"orders": {
"type": "json",
"default": "[{\"id\": \"demo-1\", \"title\": \"Order #1\", \"status\": \"Preparing\"}]"
}
}
Related guides
Native UI libraries · Chat buttons and pages · Full catalog vocabulary · Tool grants and permissions