Skip to Content
GuidesProteus

Proteus

Proteus is a JSON-based UI specification for building interactive tool interfaces. You define your UI as a JSON document, and the Proteus renderer (@optiaxiom/proteus) turns it into interactive Axiom components.

Document structure

A Proteus document is a JSON object with $type: "Document". At minimum it needs a body. Every element has a $type that identifies the component. The children property holds nested content: a string, number, another element, or an array of elements.

Welcome to your dashboard

Proteus turns a JSON description into a fully interactive Axiom UI.

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer element={{ $type: "Document", body: [ { $type: "Text", children: "Proteus turns a JSON description into a fully interactive Axiom UI.", }, ], title: "Welcome to your dashboard", }} /> </Box> ); }

Documents also support title, subtitle, appName, appIcon, and actions (buttons rendered at the bottom).

Opal

Create your test plan

Select how you'd like to define the page or experience.

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; import { useState } from "react"; export function App() { const [data, setData] = useState<Record<string, unknown>>({}); return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer data={data} element={{ $type: "Document", actions: [ { $type: "Action", appearance: "primary-opal", children: "Create Test Plan", }, ], appName: "Opal", blocking: true, body: [ { $type: "Field", children: { $type: "Input", name: "url", placeholder: "Add a URL", }, label: "URL", }, { $type: "Field", children: { $type: "Textarea", name: "test_idea", placeholder: "e.g., Add quantity badges to product thumbnails to show how many of each item they're buying", }, label: "Test Idea", }, ], subtitle: "Select how you'd like to define the page or experience.", title: "Create your test plan", }} onDataChange={setData} /> </Box> ); }

Components

Use Group as a flexbox container to arrange child elements. It supports flexDirection, gap, alignItems, and justifyContent. Card, CardHeader, and CardLink provide card-based layouts. Separator adds a visual divider.

Add quantity badges to product thumbnails

TSK-8526

D-Congress 2026 - Digital screen content

TSK-9102

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer element={{ $type: "Document", body: { $type: "Group", border: "1", borderColor: "border.tertiary", children: [ { $type: "Group", children: [ { $type: "Text", children: "Add quantity badges to product thumbnails", fontWeight: "600", }, { $type: "Text", children: "TSK-8526", color: "fg.tertiary", fontSize: "sm", }, ], flexDirection: "column", gap: "4", p: "12", }, { $type: "Separator", borderColor: "border.tertiary" }, { $type: "Group", children: [ { $type: "Text", children: "D-Congress 2026 - Digital screen content", fontWeight: "600", }, { $type: "Text", children: "TSK-9102", color: "fg.tertiary", fontSize: "sm", }, ], flexDirection: "column", gap: "4", p: "12", }, ], flexDirection: "column", rounded: "md", }, }} /> </Box> ); }

Heading renders section headings, Text renders inline or block text, and Link renders a hyperlink with an href prop.

Key Insight

Initial performance metrics reveal a 12% drop in user retention post-update. Immediate deep-dive into Android Scrum Project's V2.2 onboarding flow is critical to reverse the trend and secure Q3 engagement goals.

View task TSK-98
"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer element={{ $type: "Document", body: [ { $type: "Heading", children: "Key Insight", level: "4" }, { $type: "Text", children: "Initial performance metrics reveal a 12% drop in user retention post-update. Immediate deep-dive into Android Scrum Project's V2.2 onboarding flow is critical to reverse the trend and secure Q3 engagement goals.", color: "fg.secondary", fontSize: "sm", }, { $type: "Link", children: "View task TSK-98", href: "https://example.com/task/tsk-98", }, ], }} /> </Box> ); }

DataTable renders structured data with columns, sorting, and pagination. Chart renders bar or line charts. Image and ImageCarousel display images. Avatar, Badge, and Time handle user avatars, status tags, and formatted timestamps.

Salesforce CRM

Q4 2024 Sales Performance

October 1 - December 31, 2025

Rank
Representative
Deals Closed
Revenue
1Sarah Chen47$2.8M
2Michael Wong42$2.5M
3Jenn Taylor39$2.3M
4David Smith35$2.1M
5Emily Johnson33$2.0M
"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer element={{ $type: "Document", appName: "Salesforce CRM", body: { $type: "DataTable", columns: [ { accessorKey: "rank", header: "Rank", size: 80 }, { accessorKey: "representative", header: "Representative" }, { accessorKey: "deals", header: "Deals Closed", size: 120 }, { accessorKey: "revenue", header: "Revenue", size: 120 }, ], data: [ { deals: "47", rank: "1", representative: "Sarah Chen", revenue: "$2.8M", }, { deals: "42", rank: "2", representative: "Michael Wong", revenue: "$2.5M", }, { deals: "39", rank: "3", representative: "Jenn Taylor", revenue: "$2.3M", }, { deals: "35", rank: "4", representative: "David Smith", revenue: "$2.1M", }, { deals: "33", rank: "5", representative: "Emily Johnson", revenue: "$2.0M", }, ], }, subtitle: "October 1 - December 31, 2025", title: "Q4 2024 Sales Performance", }} /> </Box> ); }

Wrap inputs with Field to add a label. Available inputs include Input, Textarea, Select (composed from SelectTrigger and SelectContent), Switch, Range, and Question (a multi-question dynamic form).

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; import { useState } from "react"; export function App() { const [data, setData] = useState<Record<string, unknown>>({}); return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer data={data} element={{ $type: "Document", body: [ { $type: "Field", children: { $type: "Select", children: [ { $type: "SelectTrigger", w: "full" }, { $type: "SelectContent" }, ], name: "target_by", options: [ { label: "URL", value: "url" }, { label: "Saved Pages", value: "page" }, ], }, label: "Target by", }, { $type: "Field", children: { $type: "Input", name: "url", placeholder: "Add a URL", }, label: "URL", }, { $type: "Field", children: { $type: "Textarea", name: "test_idea", placeholder: "e.g., Add quantity badges to product thumbnails to show how many of each item they're buying", }, label: "Test Idea", }, { $type: "Field", children: { $type: "Switch", name: "include_metadata" }, label: "Include Metadata", }, ], }} onDataChange={setData} /> </Box> ); }

Action renders a button with an onClick handler (see Interactions below). Use appearance (primary, danger, subtle, etc.) to style the button.

Content Marketing Platform

Version 2.2 Performance Optimization

Android Scrum Campaign / TSK-98

Initial performance metrics reveal a 12% drop in user retention post-update.

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer element={{ $type: "Document", actions: [ { $type: "Action", children: "Comment" }, { $type: "Action", appearance: "primary", children: "View task", }, ], appName: "Content Marketing Platform", body: [ { $type: "Text", children: "Initial performance metrics reveal a 12% drop in user retention post-update.", }, ], subtitle: "Android Scrum Campaign / TSK-98", title: "Version 2.2 Performance Optimization", }} /> </Box> ); }

All components accept Axiom styling props for spacing, colors, layout, and typography:

TOTAL REVENUE

$204M

+12% vs last quarter

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer element={{ $type: "Document", body: { $type: "Group", border: "1", borderColor: "border.tertiary", children: [ { $type: "Text", children: "TOTAL REVENUE", color: "fg.tertiary", fontSize: "xs", textTransform: "uppercase", }, { $type: "Text", children: "$204M", fontSize: "2xl", fontWeight: "700", }, { $type: "Text", children: "+12% vs last quarter", color: "fg.success.strong", fontSize: "sm", }, ], flexDirection: "column", gap: "4", p: "12", rounded: "xl", }, }} /> </Box> ); }

Data binding

Reads a field from the tool response using a JSON Pointer path. Paths starting with / are absolute (from the root of the tool response). Paths without a leading / are relative (resolved from the current context, like inside a Map).

TOTAL REVENUE

$204M

+12% vs last quarter

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer data={{ label: "TOTAL REVENUE", trend: "+12% vs last quarter", trendColor: "fg.success.strong", value: "$204M", }} element={{ $type: "Document", body: { $type: "Group", border: "1", borderColor: "border.tertiary", children: [ { $type: "Text", children: { $type: "Value", path: "label" }, color: "fg.tertiary", fontSize: "xs", textTransform: "uppercase", }, { $type: "Text", children: { $type: "Value", path: "value" }, fontSize: "2xl", fontWeight: "700", }, { $type: "Text", children: { $type: "Value", path: "trend" }, color: { $type: "Value", path: "trendColor" }, fontSize: "sm", }, ], flex: "1", flexDirection: "column", gap: "4", p: "12", rounded: "xl", }, }} /> </Box> ); }

Iterates over an array, rendering children once per item. Inside a Map, relative paths resolve against the current item:

TOTAL REVENUE

$204M

+12% vs last quarter

TOTAL CLOSE RATE

83%

-3% vs last quarter

TOTAL DEALS CLOSED

230

+18 vs last quarter

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer data={{ metrics: [ { label: "TOTAL REVENUE", trend: "+12% vs last quarter", trendColor: "fg.success.strong", value: "$204M", }, { label: "TOTAL CLOSE RATE", trend: "-3% vs last quarter", trendColor: "fg.error.strong", value: "83%", }, { label: "TOTAL DEALS CLOSED", trend: "+18 vs last quarter", trendColor: "fg.success.strong", value: "230", }, ], }} element={{ $type: "Document", body: { $type: "Group", children: { $type: "Map", children: { $type: "Group", border: "1", borderColor: "border.tertiary", children: [ { $type: "Text", children: { $type: "Value", path: "label" }, color: "fg.tertiary", fontSize: "xs", textTransform: "uppercase", }, { $type: "Text", children: { $type: "Value", path: "value" }, fontSize: "2xl", fontWeight: "700", }, { $type: "Text", children: { $type: "Value", path: "trend" }, color: { $type: "Value", path: "trendColor" }, fontSize: "sm", }, ], flex: "1", flexDirection: "column", gap: "4", p: "12", rounded: "xl", }, path: "/metrics", }, gap: "16", }, }} /> </Box> ); }

MapIndex gives you the current iteration index inside a Map. Concat takes a children array and joins each resolved value into a single string. Zip takes a sources object — each key becomes a property name, and the values (arrays or expressions resolving to arrays) are zipped row-wise into an array of objects, useful as Chart.data or DataTable.data.

UTM Creation

Click the button to see how Concat formats the parameter values into a single message.

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box, toaster } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer data={{ parameters: [ { name: "Campaign Name", value: "spring-sale-2024" }, { name: "Landing Page URL", value: "https://example.com/landing" }, { name: "Channel", value: null }, ], }} element={{ $type: "Document", actions: [ { $type: "Action", appearance: "primary-opal", children: "Run agent", onClick: { message: { $type: "Map", children: { $type: "Concat", children: [ { $type: "Value", path: "name" }, ": ", { $type: "Show", children: "[Not specified]", when: { "!": { $type: "Value", path: "value" } }, }, { $type: "Show", children: { $type: "Value", path: "value" }, when: { "!!": { $type: "Value", path: "value" } }, }, ], }, path: "/parameters", separator: "\n", }, }, }, ], body: [ { $type: "Text", children: "Click the button to see how Concat formats the parameter values into a single message.", }, ], title: "UTM Creation", }} onMessage={(msg) => { toaster.create(typeof msg === "string" ? msg : JSON.stringify(msg)); }} /> </Box> ); }

This template renders a list of search results dynamically from a tool response:

Content Marketing Platform

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer data={{ table_data: [ { cmp_url: "https://example.com/task/id-123", owner: "John Doe", reference: "TSK-8526", status: "Overdue", title: "Add quantity badges to product thumbnails", }, { cmp_url: "https://example.com/task/id-345", owner: "Jane Doe", reference: "TSK-9102", status: "In Progress", title: "D-Congress 2026 - Digital screen content", }, ], total_results: 2, }} element={{ $type: "Document", appName: "Content Marketing Platform", body: { $type: "Map", children: { $type: "Card", children: { $type: "CardHeader", children: { $type: "CardLink", children: { $type: "Value", path: "title" }, href: { $type: "Value", path: "cmp_url" }, }, description: { $type: "Value", path: "reference" }, }, }, path: "/table_data", }, title: [{ $type: "Value", path: "/total_results" }, " results found"], }} /> </Box> ); }

Conditional rendering

Use Show to render content only when a condition is met:

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; import { useState } from "react"; export function App() { const [data, setData] = useState<Record<string, unknown>>({ target_by: "url", }); return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer data={data} element={{ $type: "Document", body: [ { $type: "Field", children: { $type: "Select", children: [ { $type: "SelectTrigger", w: "full" }, { $type: "SelectContent" }, ], name: "target_by", options: [ { label: "URL", value: "url" }, { label: "Saved Pages", value: "page" }, ], }, label: "Target by", }, { $type: "Show", children: { $type: "Field", children: { $type: "Input", name: "url", placeholder: "Add a URL", }, label: "URL", }, when: { "==": [{ $type: "Value", path: "/target_by" }, "url"], }, }, { $type: "Show", children: { $type: "Field", children: { $type: "Select", children: [ { $type: "SelectTrigger", w: "full" }, { $type: "SelectContent" }, ], name: "saved_page", options: [ { label: "Home page", value: "home" }, { label: "Marketplace", value: "marketplace" }, { label: "Product Details", value: "product_details" }, ], }, label: "Saved Page", }, when: { "==": [{ $type: "Value", path: "/target_by" }, "page"], }, }, ], }} onDataChange={setData} /> </Box> ); }

Supported operators: ==, !=, <, <=, >, >=, !! (truthy), ! (falsy). Combine conditions with and and or:

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; import { useState } from "react"; export function App() { const [data, setData] = useState<Record<string, unknown>>({ target_by: "url", url: "https://example.com", }); return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer data={data} element={{ $type: "Document", body: [ { $type: "Field", children: { $type: "Select", children: [ { $type: "SelectTrigger", w: "full" }, { $type: "SelectContent" }, ], name: "target_by", options: [ { label: "URL", value: "url" }, { label: "Saved Pages", value: "page" }, ], }, label: "Target by", }, { $type: "Show", children: { $type: "Field", children: { $type: "Textarea", name: "test_idea", placeholder: "e.g., Add quantity badges to product thumbnails", }, label: "Test Idea", }, when: { or: [ { and: [ { "==": [{ $type: "Value", path: "/target_by" }, "url"], }, { "!!": { $type: "Value", path: "/url" } }, ], }, { and: [ { "==": [{ $type: "Value", path: "/target_by" }, "page"], }, { "!!": { $type: "Value", path: "/saved_page" } }, ], }, ], }, }, ], }} onDataChange={setData} /> </Box> ); }

Interactions

Sends the named interaction back to your server, where it can be handled and responded to:

Content Marketing Platform

Version 2.2 Performance Optimization

Android Scrum Campaign / TSK-98

Initial performance metrics reveal a 12% drop in user retention post-update.

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer element={{ $type: "Document", actions: [ { $type: "Action", children: "Comment", onClick: { interaction: "comment_on_task" }, }, { $type: "Action", appearance: "primary", children: "View task", onClick: { interaction: "view_task" }, }, ], appName: "Content Marketing Platform", body: [ { $type: "Text", children: "Initial performance metrics reveal a 12% drop in user retention post-update.", }, ], subtitle: "Android Scrum Campaign / TSK-98", title: "Version 2.2 Performance Optimization", }} /> </Box> ); }

Sends a text message back to the LLM:

Content Marketing Platform

Version 2.2 Performance Optimization

Android Scrum Campaign / TSK-98

Initial performance metrics reveal a 12% drop in user retention post-update.

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer element={{ $type: "Document", actions: [ { $type: "Action", children: "Comment", onClick: { message: "I'd like to leave a comment on this task.", }, }, { $type: "Action", appearance: "primary", children: "View task", onClick: { message: "Show me the full details for TSK-98.", }, }, ], appName: "Content Marketing Platform", body: [ { $type: "Text", children: "Initial performance metrics reveal a 12% drop in user retention post-update.", }, ], subtitle: "Android Scrum Campaign / TSK-98", title: "Version 2.2 Performance Optimization", }} /> </Box> ); }

Triggers a file download:

Strategic Pitch Presentation

Google Slides

"use client"; import { ProteusDocumentRenderer } from "@optiaxiom/proteus"; import { Box } from "@optiaxiom/react"; export function App() { return ( <Box maxW="md" w="full"> <ProteusDocumentRenderer data={{ download_url: "https://example.com/files/strategic-pitch-presentation.pptx", }} element={{ $type: "Document", actions: [ { $type: "Action", appearance: "primary", children: "Download", onClick: { action: "download", url: { $type: "Value", path: "/download_url" }, }, }, ], body: [ { $type: "Image", alt: "Slide preview of Strategic Pitch Presentation", src: "https://placehold.co/560x315", }, ], subtitle: "Google Slides", title: "Strategic Pitch Presentation", }} /> </Box> ); }

Proteus Designer

The Proteus Designer is a visual editor for building Proteus documents. You can build a component tree, edit properties in the inspector, see a live preview of how the document renders, and copy the final JSON into your resource handler. You can also provide sample data to test how dynamic values resolve.

Element reference

actions

Actions available for this document

Node
appearance

Visual treatment of the document shell. 'default' renders the document as a card with background, border, and padding. 'inline' strips the surrounding chrome so the document blends into its host container.

"default" | "inline" | Expression
appIcon

URL or data URI for the application icon (e.g., 'https://example.com/icon.png' or 'data:image/svg+xml,...'). Rendered as an <img> element.

string
appName

The official name of the application

string
blocking

If true, hides chat prompt and forces user interaction with document. User can press ESC or close to abandon.

boolean
body*

The main content of the document.

Node
compact

If true, constrains the body to a max height and makes it scrollable when content overflows.

boolean
data

Initial data for the document. Not used by the renderer directly — intended for the outer component managing state to use as the starting data.

object
meta

Additional metadata not directly consumed by Proteus. Use this to pass along any extra data.

any
subtitle

A brief description or tagline that provides additional context about the Proteus document's purpose.

Node
title

A concise heading that encapsulates the essence of the Proteus document's content or intended action.

Node
titleIcon

URL or data URI for an icon displayed alongside the title in a block-style header.

string
alignItems

Set the element's align-items CSS property. Defaults to center when flexDirection='row', and stretch when flexDirection='column'.

"stretch" | "center" | "end" | "start" | "normal" | Expression
children
Node
flexDirection

Set the element's flex-direction CSS property. Default: 'row' (CSS standard)

"column" | "column-reverse" | "row" | "row-reverse" | Expression
children
Node
addonAfter

Display content inside the header after children.

Node
addonBefore

Display content inside the header before children.

Node
children
Node
description

Add secondary text after the primary title.

Node
lineClamp

Truncate the text at specific number of lines.

"2" | "4" | "1" | "3" | Expression
children
Node
href

The link href.

string | Expression
onClick

Action triggered when link is clicked

EventHandler

Accepts only $type plus the standard styling props.

children
Node
level

Heading level (1-4) that controls both the semantic HTML tag and font size. - level="1": renders <h1> with fontSize="4xl" (default) - level="2": renders <h2> with fontSize="3xl" - level="3": renders <h3> with fontSize="2xl" - level="4": renders <h4> with fontSize="xl" Use asChild to decouple the semantic level from visual appearance.

"2" | "4" | "1" | "3" | Expression
children
Node
lineClamp

Truncate the text at specific number of lines.

"2" | "4" | "1" | "3" | Expression
truncate

Whether to truncate the text and add an ellipsis at the end.

boolean | Expression
children
Node
href

The link href.

string | Expression
columns
Array | Expression
data
Array | Expression | Zip
data

Chart data records, either inline, a ProteusExpression, or a ProteusZip transformation

Array | Expression | Zip
layout

Chart layout direction

"horizontal" | "vertical"
series
Array | Expression
type

Chart type

"bar" | "line"
xAxisKey

Key in data records for x-axis labels

string
alt

Alternative text for the image

Expression | string
src

The image source URL

Expression | string
images*

Array of image data to display in the carousel

Array | Expression
title

Accessible label for the carousel region.

Expression | string
children
Node
colorScheme

Control the avatar fallback background and text colors.

"purple" | "neutral" | Expression
fallback

The fallback icon to display when no name or image is given.

"opal" | "team" | "user" | Expression
name

Use name to generate initials to show inside the avatar.

string | Expression
size

Control the size of the avatar.

"xs" | "sm" | "md" | "lg" | "xl" | "3xl" | "2xs" | Expression
src

Render the image inside the avatar.

string | Expression
children
Node
intent

Control the appearance by selecting between the different badge types.

"information" | "success" | "warning" | "danger" | "neutral" | "primary" | Expression
date*

The date to display. Can be a Date object or an ISO 8601 string.

string | Expression
showDate

Whether to show the date part of the value. Defaults to true.

boolean | Expression
showTime

Whether to show the time part of the value. Defaults to false.

boolean | Expression
children
Node
description

Provide description and help text for the field.

Node
info

Display a help icon with additional context for the input.

Node
label

The label of the field.

Node
required

Display an asterisk for required inputs.

boolean | Expression
addonAfter

Display content inside the input at the end.

Node
addonBefore

Display content inside the input at the start.

Node
appearance

Control the appearance of the input.

"number" | "default" | Expression
autoFocus

Whether the input should be focused on mount.

boolean | Expression
name

The name of the form control element.

string | Expression
placeholder

The placeholder text to use when control has no value.

string | Expression
required

Whether selecting this input is required.

boolean | Expression
type

The input type.

"number" | "color" | "button" | "checkbox" | "radio" | "hidden" | "text" | "reset" | "range" | "search" | "time" | "image" | "tel" | "url" | "email" | "date" | "submit" | "month" | "datetime-local" | "week" | "file" | "password" | string | Expression
maxRows

Limits the height of the textarea when resize=auto is used.

1 | 2 | 3 | 4 | 5 | Expression
name

The name of the form control element.

string | Expression
placeholder

The placeholder text to use when control has no value.

string | Expression
required

Whether selecting this input is required.

boolean | Expression
resize

Control whether resizing mode is manual, automatic, or disabled.

"none" | "auto" | "vertical" | Expression
rows

The number of rows to display.

number | Expression
children
Node
name

The name of the inner select element.

string | Expression
options*

The select items/options we want to render.

Array
required

Whether the select value is required.

boolean | Expression
children
Node

Accepts only $type plus the standard styling props.

children
Node
description

Add secondary text after the label.

Node
name

The name of the form control element.

string | Expression
required

Whether selecting this input is required.

boolean | Expression
marks

The marks to display on the range steps.

Array
max

The maximum value for the range.

number | Expression
min

The minimum value for the range.

number | Expression
step

The stepping interval for the range.

number | Expression
questions*

Array of questions data

Expression
appearance

Control the appearance by selecting between the different button types.

"default" | "danger" | "primary" | "subtle" | "danger-outline" | "default-opal" | "inverse" | "primary-opal" | Expression
children
Node
type

The default behavior of the button.

"button" | "reset" | "submit" | Expression
onClick

Action triggered when button is clicked

EventHandler
appearance

Control the appearance by selecting between the different button types.

"default" | "danger" | "primary" | "subtle" | "danger-outline" | "default-opal" | "inverse" | "primary-opal" | Expression
children
Node
type

The default behavior of the button.

"button" | "reset" | "submit" | Expression
onClick

Action triggered when button is clicked

EventHandler
formatter

Optional formatter to apply to the resolved value. Can be a string shorthand or an object with type and options for Intl formatters.

"DateTime" | "Number" | object
path*

Path to a value in the data. Absolute paths start with '/' and resolve from the root (e.g., '/title', '/options/0/label'). Inside a Map template, paths without a leading '/' are relative to the current item (e.g., 'title' resolves to each item's 'title' field).

string
children

Template object to render for each item in the array. Value paths inside this template are relative to the current item (e.g., path='title' resolves to each item's 'title' field). Use a leading '/' to reference top-level data (e.g., path='/title' resolves to the root data's 'title').

Node
flat

When true, flattens the result array by one level. Useful when each mapped item resolves to an array and you want a single flat list.

boolean
path*

JSON pointer path to the source array in the data (e.g., '/results')

string
separator

Optional separator to render between items. Can be a string or a ProteusNode for more complex separators.

Node

Accepts only $type plus the standard styling props.

children

Array of values to concatenate into a single string. Each item is resolved and joined together.

Array
sources*

Map of output property names to array sources. Each source should resolve to an array of the same length.

object
children

Content to show when condition is true

Node
when

Single condition or array of conditions (AND logic). Each condition is an object with one operator key.

Condition | Array

Accepts only $type plus the standard styling props.

fallback

Content rendered on platforms without iframe support (Teams, Slack, mobile). If omitted, a default 'View in Opal web' message is shown.

Node
height

Height of the iframe in pixels

number
resource*

Resource URI identifying the MCP app to render (e.g., 'ui://sample-widget')

string
Last updated on