Advanced Components

Conditional, Loop, Accordion, Section, Icon, Fragment, Slot, Custom

Advanced Components

Components for dynamic rendering and specialized use cases.

Conditional

Conditional rendering based on expressions.

json
{
  "type": "Conditional",
  "condition": "{{state.isLoggedIn}}",
  "then": { "type": "Text", "content": "Welcome back!" },
  "else": { "type": "Button", "label": "Sign In" }
}

Properties

PropertyTypeDefaultDescription
conditionstring-Expression to evaluate (required)
thenobject-Component when true (required)
elseobject-Component when false (optional)

Condition Syntax

json
// Boolean state
"condition": "{{state.isActive}}"

// Comparison
"condition": "{{state.count}} > 0"
"condition": "{{state.status}} === 'completed'"

// Logical operators
"condition": "{{state.isAdmin}} && {{state.hasPermission}}"
"condition": "{{state.isEmpty}} || {{state.isLoading}}"

// Negation
"condition": "!{{state.hasError}}"

// Complex
"condition": "({{state.role}} === 'admin' || {{state.role}} === 'manager') && {{state.isVerified}}"

Examples

Loading state:

json
{
  "type": "Conditional",
  "condition": "{{state.isLoading}}",
  "then": { "type": "Skeleton", "variant": "rectangular", "height": "200px" },
  "else": { "type": "Table", "dataSource": "state:items" }
}

Empty state:

json
{
  "type": "Conditional",
  "condition": "{{state.items.length}} === 0",
  "then": {
    "type": "EmptyState",
    "title": "No Items",
    "description": "Create your first item",
    "icon": "Inbox"
  },
  "else": { "type": "List", "dataSource": "state:items" }
}

Role-based access:

json
{
  "type": "Conditional",
  "condition": "{{state.user.role}} === 'admin'",
  "then": {
    "type": "Button",
    "label": "Admin Settings",
    "events": {
      "on_click": [{ "type": "navigate", "to": "/admin" }]
    }
  }
}

Nested conditions:

json
{
  "type": "Conditional",
  "condition": "{{state.status}} === 'loading'",
  "then": { "type": "Skeleton", "variant": "text" },
  "else": {
    "type": "Conditional",
    "condition": "{{state.status}} === 'error'",
    "then": {
      "type": "Alert",
      "variant": "destructive",
      "message": "{{state.error}}"
    },
    "else": { "type": "Text", "content": "{{state.data}}" }
  }
}

Loop

Iterate over arrays to render repeated content.

json
{
  "type": "Loop",
  "dataSource": "state:items",
  "template": {
    "type": "Card",
    "title": "{{$item.name}}",
    "content": { "type": "Text", "content": "{{$item.description}}" }
  }
}

Properties

PropertyTypeDefaultDescription
dataSourcestring-Data source path (required)
templateobject-Component template for each item (required)
emptyTemplateobject-Component when data is empty

Loop Variables

Inside template, you have access to:

VariableDescription
$itemCurrent item
$indexZero-based index
$rowAlias for $item (table context)

Examples

Basic list:

json
{
  "type": "Loop",
  "dataSource": "state:users",
  "template": {
    "type": "Flex",
    "align": "center",
    "gap": "1rem",
    "className": "p-4 border-b",
    "children": [
      {
        "type": "Avatar",
        "src": "{{$item.avatar}}",
        "fallback": "{{$item.initials}}"
      },
      {
        "type": "Flex",
        "direction": "column",
        "children": [
          {
            "type": "Text",
            "content": "{{$item.name}}",
            "className": "font-medium"
          },
          {
            "type": "Text",
            "variant": "muted",
            "content": "{{$item.email}}"
          }
        ]
      }
    ]
  }
}

Grid of cards:

json
{
  "type": "Grid",
  "columns": { "sm": 1, "md": 2, "lg": 3 },
  "gap": "1rem",
  "children": [
    {
      "type": "Loop",
      "dataSource": "state:products",
      "template": {
        "type": "Card",
        "className": "overflow-hidden",
        "content": {
          "type": "Container",
          "children": [
            {
              "type": "Image",
              "src": "{{$item.image}}",
              "className": "w-full h-48 object-cover"
            },
            {
              "type": "Container",
              "className": "p-4",
              "children": [
                { "type": "Heading", "level": 3, "text": "{{$item.name}}" },
                { "type": "Text", "content": "${{$item.price}}" }
              ]
            }
          ]
        }
      }
    }
  ]
}

With index:

json
{
  "type": "Loop",
  "dataSource": "state:items",
  "template": {
    "type": "Flex",
    "className": "p-4",
    "children": [
      { "type": "Text", "content": "{{$index + 1}}. {{$item.name}}" }
    ]
  }
}

With empty state:

json
{
  "type": "Loop",
  "dataSource": "state:items",
  "template": {
    "type": "Card",
    "title": "{{$item.name}}"
  },
  "emptyTemplate": {
    "type": "EmptyState",
    "title": "No items found",
    "icon": "Inbox"
  }
}

Accordion

Collapsible content sections.

json
{
  "type": "Accordion",
  "items": [
    {
      "key": "section-1",
      "title": "Section 1",
      "content": { "type": "Text", "content": "Content for section 1" }
    },
    {
      "key": "section-2",
      "title": "Section 2",
      "content": { "type": "Text", "content": "Content for section 2" }
    }
  ]
}

Properties

PropertyTypeDefaultDescription
itemsarray[]Accordion items (required)
type_single | multiplesingleSelection mode
defaultOpenarray[]Initially expanded keys
collapsiblebooleantrueAllow collapse all
classNamestring-CSS classes

Item Definition

PropertyTypeDescription
keystringUnique item identifier
titlestringItem header text
contentobjectItem body component
disabledboolean | stringDisabled state

Examples

FAQ section:

json
{
  "type": "Accordion",
  "type_": "single",
  "collapsible": true,
  "items": [
    {
      "key": "faq-1",
      "title": "What is Orbis?",
      "content": {
        "type": "Text",
        "content": "Orbis is a desktop application platform with plugin support."
      }
    },
    {
      "key": "faq-2",
      "title": "How do I install plugins?",
      "content": {
        "type": "Text",
        "content": "Copy WASM plugin files to the plugins directory."
      }
    },
    {
      "key": "faq-3",
      "title": "Is Orbis open source?",
      "content": {
        "type": "Text",
        "content": "Yes, Orbis is open source under the MIT license."
      }
    }
  ]
}

Multiple open:

json
{
  "type": "Accordion",
  "type_": "multiple",
  "defaultOpen": ["section-1"],
  "items": [
    {
      "key": "section-1",
      "title": "General Settings",
      "content": {
        "type": "Form",
        "id": "general",
        "fields": [
          { "name": "name", "fieldType": "text", "label": "Name" }
        ]
      }
    },
    {
      "key": "section-2",
      "title": "Advanced Settings",
      "content": {
        "type": "Form",
        "id": "advanced",
        "fields": [
          { "name": "apiKey", "fieldType": "text", "label": "API Key" }
        ]
      }
    }
  ]
}

Section

Semantic grouping with optional collapsible header.

json
{
  "type": "Section",
  "title": "User Details",
  "description": "Personal information",
  "children": [
    { "type": "DataDisplay", "label": "Name", "value": "{{user.name}}" },
    { "type": "DataDisplay", "label": "Email", "value": "{{user.email}}" }
  ]
}

Properties

PropertyTypeDefaultDescription
titlestring-Section title
descriptionstring-Section description
childrenarray[]Child components (required)
collapsiblebooleanfalseMake section collapsible
defaultCollapsedbooleanfalseInitially collapsed
classNamestring-CSS classes

Examples

Basic section:

json
{
  "type": "Section",
  "title": "Account Settings",
  "description": "Manage your account preferences",
  "children": [
    {
      "type": "Form",
      "id": "account",
      "fields": [
        { "name": "email", "fieldType": "email", "label": "Email" },
        { "name": "password", "fieldType": "password", "label": "Password" }
      ]
    }
  ]
}

Collapsible section:

json
{
  "type": "Section",
  "title": "Advanced Options",
  "collapsible": true,
  "defaultCollapsed": true,
  "children": [
    { "type": "Text", "content": "Advanced configuration options..." }
  ]
}

Icon

Display icons from lucide-react.

json
{
  "type": "Icon",
  "name": "Settings",
  "size": "md"
}

Properties

PropertyTypeDefaultDescription
namestring-Icon name (required)
sizexs | sm | md | lg | xlmdIcon size
colorstring-Icon color (CSS color)
classNamestring-CSS classes
eventsobject-Event handlers

Sizes

SizeDimension
xs12px
sm16px
md20px
lg24px
xl32px

Events

EventTrigger
onClickIcon clicked

Examples

Different sizes:

json
{
  "type": "Flex",
  "gap": "1rem",
  "align": "center",
  "children": [
    { "type": "Icon", "name": "Star", "size": "xs" },
    { "type": "Icon", "name": "Star", "size": "sm" },
    { "type": "Icon", "name": "Star", "size": "md" },
    { "type": "Icon", "name": "Star", "size": "lg" },
    { "type": "Icon", "name": "Star", "size": "xl" }
  ]
}

With color:

json
{
  "type": "Icon",
  "name": "CheckCircle",
  "size": "lg",
  "color": "#22c55e"
}

Clickable icon:

json
{
  "type": "Icon",
  "name": "Settings",
  "size": "md",
  "className": "cursor-pointer",
  "events": {
    "on_click": [{ "type": "navigate", "to": "/settings" }]
  }
}

Dynamic icon:

json
{
  "type": "Icon",
  "name": "{{state.status === 'success' ? 'CheckCircle' : 'AlertCircle'}}",
  "color": "{{state.status === 'success' ? '#22c55e' : '#ef4444'}}"
}

Common Icons

CategoryIcons
NavigationHome, ArrowLeft, ArrowRight, ChevronDown, Menu
ActionsPlus, Edit, Trash, Download, Upload, Copy
StatusCheck, X, AlertTriangle, Info, HelpCircle
UserUser, Users, Settings, LogOut, Bell
FilesFile, FileText, Folder, FolderOpen, Image
DataDatabase, Table, BarChart, LineChart, PieChart

Browse all icons at lucide.dev.


Fragment

Invisible wrapper for grouping components without extra DOM nodes.

json
{
  "type": "Fragment",
  "children": [
    { "type": "Text", "content": "First" },
    { "type": "Text", "content": "Second" }
  ]
}

Properties

PropertyTypeDefaultDescription
childrenarray[]Child components (required)

Use Cases

Return multiple elements:

json
{
  "type": "Conditional",
  "condition": "{{state.showDetails}}",
  "then": {
    "type": "Fragment",
    "children": [
      { "type": "Divider" },
      { "type": "Text", "content": "Additional details..." },
      { "type": "Button", "label": "Learn More" }
    ]
  }
}

In loop:

json
{
  "type": "Loop",
  "dataSource": "state:items",
  "template": {
    "type": "Fragment",
    "children": [
      { "type": "Heading", "level": 3, "text": "{{$item.title}}" },
      { "type": "Text", "content": "{{$item.description}}" },
      { "type": "Divider" }
    ]
  }
}

Slot

Placeholder for plugin-defined content.

json
{
  "type": "Slot",
  "name": "sidebar-widgets",
  "fallback": { "type": "Text", "content": "No widgets available" }
}

Properties

PropertyTypeDefaultDescription
namestring-Slot identifier (required)
fallbackobject-Fallback content when slot empty

Use Cases

Slots allow plugins to inject content into predefined areas:

json
{
  "type": "Container",
  "children": [
    { "type": "PageHeader", "title": "Dashboard" },
    {
      "type": "Grid",
      "columns": { "lg": 3 },
      "gap": "1rem",
      "children": [
        {
          "type": "Slot",
          "name": "dashboard-widget-1",
          "fallback": { "type": "Card", "title": "Widget 1" }
        },
        {
          "type": "Slot",
          "name": "dashboard-widget-2",
          "fallback": { "type": "Card", "title": "Widget 2" }
        },
        {
          "type": "Slot",
          "name": "dashboard-widget-3",
          "fallback": { "type": "Card", "title": "Widget 3" }
        }
      ]
    }
  ]
}

Custom

Render a custom component registered by the host application.

json
{
  "type": "Custom",
  "component": "MySpecialChart",
  "props": {
    "data": "{{state.chartData}}",
    "options": {
      "showLegend": true
    }
  }
}

Properties

PropertyTypeDefaultDescription
componentstring-Registered component name (required)
propsobject{}Props to pass to component
classNamestring-CSS classes

Example

If the host app registers a MapView component:

json
{
  "type": "Custom",
  "component": "MapView",
  "props": {
    "center": "{{state.location}}",
    "zoom": 14,
    "markers": "{{state.markers}}"
  }
}

Advanced Patterns

State Machine Pattern

json
{
  "type": "Container",
  "children": [
    {
      "type": "Conditional",
      "condition": "{{state.status}} === 'idle'",
      "then": {
        "type": "Button",
        "label": "Start",
        "events": {
          "on_click": [
            { "type": "update_state", "path": "status", "value": "loading" },
            { "type": "call_api", "api": "process" }
          ]
        }
      }
    },
    {
      "type": "Conditional",
      "condition": "{{state.status}} === 'loading'",
      "then": {
        "type": "LoadingOverlay",
        "loading": true,
        "text": "Processing...",
        "children": { "type": "Container" }
      }
    },
    {
      "type": "Conditional",
      "condition": "{{state.status}} === 'success'",
      "then": {
        "type": "Alert",
        "variant": "default",
        "title": "Success",
        "message": "Operation completed!"
      }
    },
    {
      "type": "Conditional",
      "condition": "{{state.status}} === 'error'",
      "then": {
        "type": "Alert",
        "variant": "destructive",
        "title": "Error",
        "message": "{{state.error}}"
      }
    }
  ]
}

Dynamic Form Fields

json
{
  "type": "Form",
  "id": "dynamic-form",
  "fields": [
    {
      "type": "Loop",
      "dataSource": "state:formSchema.fields",
      "template": {
        "type": "Conditional",
        "condition": "{{$item.visible}} !== false",
        "then": {
          "name": "{{$item.name}}",
          "fieldType": "{{$item.type}}",
          "label": "{{$item.label}}",
          "bindTo": "formData.{{$item.name}}",
          "options": "{{$item.options}}"
        }
      }
    }
  ]
}

Nested Data Display

json
{
  "type": "Loop",
  "dataSource": "state:categories",
  "template": {
    "type": "Accordion",
    "items": [
      {
        "key": "{{$item.id}}",
        "title": "{{$item.name}}",
        "content": {
          "type": "Conditional",
          "condition": "{{$item.items.length}} > 0",
          "then": {
            "type": "Loop",
            "dataSource": "{{$item.items}}",
            "template": {
              "type": "Card",
              "title": "{{$item.name}}",
              "content": { "type": "Text", "content": "{{$item.description}}" }
            }
          },
          "else": {
            "type": "EmptyState",
            "title": "No items",
            "icon": "Inbox"
          }
        }
      }
    ]
  }
}