Skip to Content
CapabilitiesUI Rendering

UI Rendering: Schema-Driven Dynamic Forms

Status: MVP (v2.0.0) | Maturity: Production-Ready | Tests: 45 (31 unit + 9 integration + 5 contract)
Performance: 42ms cache hit, 127ms cache miss | Adapters: 4 (Appsmith, RJSF, ECharts, TanStack)

Cascade Platform generates rich user interfaces from JSON Schema, supporting multiple frameworks and rendering targets without writing UI code.


What is Schema-Driven UI Rendering?

Instead of building forms in React, Vue, or HTML, you define forms in JSON Schema with UI hints. Cascade automatically renders across multiple frameworks:

  • Appsmith (primary): Full-featured forms, tables, charts, dashboards
  • RJSF (secondary): Lightweight forms, perfect for mobile/simple apps
  • ECharts: Data visualization and charts
  • TanStack Table: Sortable, filterable data tables

Key benefits:

  • ✅ No UI code to maintain
  • ✅ Consistent UI across platforms
  • ✅ Dynamic forms (show/hide fields based on values)
  • ✅ Real-time validation
  • ✅ Accessible (WCAG 2.1 AA)

How It Works: CDL → JSON Schema → UI

The Rendering Pipeline

┌─────────────────────────────────────────┐ │ 1. CDL HumanTask Definition │ │ ├── ui: │ │ │ schema: urn:cascade:schema:... │ │ │ target: appsmith │ │ └── assignee, timeout, etc. │ └──────────────┬──────────────────────────┘ ┌─────────────────────────────────────────┐ │ 2. JSON Schema Lookup (URN registry) │ │ ├── Fetch schema definition │ │ ├── Resolve $ref references │ │ └── Validate schema structure │ └──────────────┬──────────────────────────┘ ┌─────────────────────────────────────────┐ │ 3. Adapter Selection │ │ ├── Appsmith → Rich forms │ │ ├── RJSF → Lightweight │ │ ├── ECharts → Visualizations │ │ └── TanStack → Data tables │ └──────────────┬──────────────────────────┘ ┌─────────────────────────────────────────┐ │ 4. Context Interpolation │ │ ├── Inject workflow data │ │ ├── Pre-populate fields │ │ └── Apply conditional visibility │ └──────────────┬──────────────────────────┘ ┌─────────────────────────────────────────┐ │ 5. Render in Browser │ │ ├── Display form/chart │ │ ├── Handle user input │ │ └── Validate & submit │ └─────────────────────────────────────────┘

JSON Schema Basics

Simple Form Schema

{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "title": "Loan Application", "properties": { "applicant_name": { "type": "string", "title": "Full Name", "minLength": 1, "maxLength": 100 }, "email": { "type": "string", "title": "Email Address", "format": "email" }, "loan_amount": { "type": "number", "title": "Loan Amount", "minimum": 1000, "maximum": 1000000, "description": "Amount requested (USD)" }, "loan_purpose": { "type": "string", "title": "Purpose", "enum": ["home", "auto", "personal", "business"], "default": "personal" }, "employment_status": { "type": "string", "enum": ["employed", "self_employed", "retired", "student", "unemployed"] } }, "required": ["applicant_name", "email", "loan_amount"], "additionalProperties": false }

Renders as:

┌─────────────────────────────────────┐ │ Loan Application │ ├─────────────────────────────────────┤ │ Full Name * │ │ [________________________] │ │ │ │ Email Address * │ │ [________________________] │ │ │ │ Loan Amount * │ │ [________________________] │ │ Amount requested (USD) │ │ │ │ Purpose │ │ [personal ▼] │ │ │ │ Employment Status │ │ [employed ▼] │ │ │ │ [ Submit ] │ └─────────────────────────────────────┘

Advanced: UI Hints & Customization

x-ui Properties

JSON Schema extended with x-ui-* properties for UI control:

{ "properties": { "credit_card": { "type": "string", "title": "Credit Card", "pattern": "^[0-9]{16}$", "x-ui-mask": "#### #### #### ####", "x-ui-placeholder": "1234 5678 9012 3456", "x-ui-type": "password", "x-ui-help": "Secured with TLS 1.3" }, "country": { "type": "string", "title": "Country", "x-ui-type": "searchable-select", "x-ui-options": { "endpoint": "/api/countries", "labelField": "name", "valueField": "code" } }, "date_of_birth": { "type": "string", "format": "date", "title": "Date of Birth", "x-ui-type": "date-picker", "x-ui-constraints": { "min": "1900-01-01", "max": "{{ now | date: 'YYYY-MM-DD' }}" } }, "cover_letter": { "type": "string", "title": "Cover Letter", "minLength": 50, "maxLength": 5000, "x-ui-type": "textarea", "x-ui-rows": 8 } } }

Conditional Visibility

Show/hide fields based on form values:

{ "properties": { "has_mortgage": { "type": "boolean", "title": "Do you have a mortgage?" }, "mortgage_amount": { "type": "number", "title": "Mortgage Balance", "x-ui-visible-if": "{{ form.has_mortgage === true }}" }, "mortgage_lender": { "type": "string", "title": "Lender Name", "x-ui-visible-if": "{{ form.has_mortgage === true }}" }, "employment_type": { "type": "string", "enum": ["w2", "1099", "self_employed"] }, "business_license": { "type": "string", "title": "Business License #", "x-ui-visible-if": "{{ form.employment_type === 'self_employed' }}" } } }

Computed Fields

Auto-calculate based on other fields:

{ "properties": { "monthly_income": { "type": "number", "title": "Monthly Income" }, "tax_rate": { "type": "number", "title": "Tax Rate (%)", "default": 25 }, "net_income": { "type": "number", "title": "Net Monthly Income", "x-ui-compute": "{{ monthly_income * (1 - tax_rate / 100) }}", "x-ui-readonly": true } } }

Rendering Adapters

1. Appsmith (Primary)

Best for: Complex applications, full-featured UI, dashboards

Features:

  • Rich forms with 50+ components
  • Embedded databases
  • Visual workflows
  • Drag-and-drop UI builder
  • Real-time collaboration
  • Built-in tables, charts, maps

CDL Usage:

- name: SubmitLoanApplication type: HumanTask ui: schema: urn:cascade:schema:loan_application target: appsmith config: theme: dark layout: tabbed embedded: true assignee: role: loan_officer timeout: 2h next: ProcessApplication

Performance:

  • Load time: 127ms (cold cache)
  • Re-render: 42ms (hot cache)
  • Forms with 100 fields: <200ms total

Example Schema → Appsmith:

{ "properties": { "applicant_info": { "type": "object", "title": "Applicant Information", "properties": { "first_name": { "type": "string", "title": "First Name" }, "last_name": { "type": "string", "title": "Last Name" } } }, "financial_info": { "type": "object", "title": "Financial Information", "properties": { "annual_income": { "type": "number" }, "existing_debts": { "type": "number" } } } }, "x-ui-layout": [ { "type": "tabs", "tabs": [ { "label": "Personal", "schema": "#/properties/applicant_info" }, { "label": "Financial", "schema": "#/properties/financial_info" } ] } ] }

2. RJSF (Secondary - Lightweight)

Best for: Simple forms, mobile apps, minimal dependencies

Features:

  • Material-UI or Bootstrap themes
  • 15+ built-in widgets
  • Custom widget support
  • Lightweight (<50KB gzip)
  • Works offline

CDL Usage:

- name: QuickApproval type: HumanTask ui: schema: urn:cascade:schema:quick_approval_form target: rjsf config: theme: material-ui compact: true timeout: 30m next: ProcessApproval

Example:

{ "title": "Quick Approval", "properties": { "approved": { "type": "boolean", "title": "Approve?" }, "notes": { "type": "string", "title": "Notes (optional)" } }, "uiSchema": { "approved": { "ui:autofocus": true }, "notes": { "ui:widget": "textarea", "ui:rows": 3 } } }

3. ECharts (Visualization)

Best for: Data visualization, dashboards, reporting

Features:

  • 30+ chart types (line, bar, pie, scatter, heatmap, etc.)
  • Real-time data updates
  • Interactive legends & tooltips
  • Export to PNG/SVG
  • Responsive design

CDL Usage:

- name: ReviewSalesMetrics type: HumanTask ui: schema: urn:cascade:schema:sales_dashboard target: echarts timeout: 1h next: ApproveForecast

Example Schema (Bar Chart):

{ "title": "Monthly Revenue", "type": "object", "properties": { "chart": { "x-ui-type": "bar-chart", "x-ui-data": { "source": [ ["Month", "Revenue", "Target"], ["Jan", 120, 100], ["Feb", 145, 110], ["Mar", 160, 120], ["Apr", 155, 130] ] }, "x-ui-options": { "series": [ { "name": "Revenue", "type": "bar" }, { "name": "Target", "type": "line" } ], "xAxis": { "type": "category" }, "yAxis": {} } } } }

4. TanStack Table (Data Grids)

Best for: Large datasets, sorting, filtering

Features:

  • Virtual scrolling (1M+ rows)
  • Column sorting & filtering
  • Pagination
  • Export to CSV/Excel
  • Cell customization

CDL Usage:

- name: ReviewApplications type: HumanTask ui: schema: urn:cascade:schema:applications_table target: tanstack config: rows_per_page: 50 enable_export: true timeout: 4h next: ProcessApplications

Example Schema:

{ "title": "Loan Applications", "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "applicant": { "type": "string" }, "amount": { "type": "number" }, "status": { "type": "string", "enum": ["pending", "approved", "rejected"] } } }, "x-ui-columns": [ { "id": "applicant", "header": "Applicant Name" }, { "id": "amount", "header": "Loan Amount", "type": "number", "format": "currency" }, { "id": "status", "header": "Status", "type": "badge" } ] }

Advanced Features

1. Dynamic Schemas

Load schema based on context:

- name: CollectApplicationDetails type: HumanTask ui: schema: "urn:cascade:schema:application_{{ $.application_type }}" # Resolves to: # - urn:cascade:schema:application_mortgage (if type=mortgage) # - urn:cascade:schema:application_auto (if type=auto) target: appsmith timeout: 2h next: ProcessApplication

2. Pre-populated Fields

Inject workflow data into form:

- name: ConfirmApplicationDetails type: HumanTask ui: schema: urn:cascade:schema:application_confirmation target: appsmith pre_populate: applicant_name: "{{ $.verified_name }}" loan_amount: "{{ $.calculated_amount }}" employment_status: "{{ $.employment_check.status }}" timeout: 1h next: ProcessApplication

3. Multi-Step Forms

Break large forms into sections:

{ "title": "Loan Application", "x-ui-steps": [ { "step": 1, "title": "Personal Information", "schema": { "type": "object", "properties": { "first_name": { "type": "string" }, "last_name": { "type": "string" }, "email": { "type": "string", "format": "email" } }, "required": ["first_name", "last_name", "email"] } }, { "step": 2, "title": "Financial Information", "schema": { "type": "object", "properties": { "annual_income": { "type": "number" }, "existing_debts": { "type": "number" } }, "required": ["annual_income"] } }, { "step": 3, "title": "Review & Submit", "schema": { "type": "object", "properties": { "confirmation": { "type": "boolean", "title": "I confirm all information is accurate" } }, "required": ["confirmation"] } } ] }

Real-World Examples

Example 1: Complex Loan Application

CDL with Appsmith rendering:

workflows: - name: ProcessLoanApplication start: CollectPersonalInfo states: - name: CollectPersonalInfo type: HumanTask ui: schema: urn:cascade:schema:personal_information target: appsmith assignee: role: loan_officer timeout: 2h next: CollectFinancialInfo - name: CollectFinancialInfo type: HumanTask ui: schema: urn:cascade:schema:financial_information target: appsmith pre_populate: applicant_name: "{{ $.personal_info.full_name }}" timeout: 2h next: ReviewAndConfirm - name: ReviewAndConfirm type: HumanTask ui: schema: urn:cascade:schema:application_review target: appsmith pre_populate: applicant_name: "{{ $.personal_info.full_name }}" email: "{{ $.personal_info.email }}" annual_income: "{{ $.financial_info.annual_income }}" loan_amount: "{{ $.financial_info.loan_amount }}" timeout: 1h next: ApplicationComplete - name: ApplicationComplete type: Task resource: urn:cascade:activity:save_application end: true

Personal Information Schema:

{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "Personal Information", "type": "object", "properties": { "full_name": { "type": "string", "title": "Full Name", "minLength": 1, "maxLength": 100 }, "email": { "type": "string", "title": "Email", "format": "email" }, "phone": { "type": "string", "title": "Phone Number", "pattern": "^[0-9\\-\\+\\(\\)\\s]{10,}$" }, "date_of_birth": { "type": "string", "title": "Date of Birth", "format": "date" }, "address": { "type": "object", "title": "Address", "properties": { "street": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" }, "zip": { "type": "string", "pattern": "^[0-9]{5}$" }, "country": { "type": "string", "default": "US" } }, "required": ["street", "city", "state", "zip"] } }, "required": ["full_name", "email", "phone", "date_of_birth", "address"], "additionalProperties": false }

Example 2: Dashboard with ECharts

Sales metrics dashboard:

{ "title": "Sales Dashboard", "type": "object", "properties": { "revenue_chart": { "x-ui-type": "line-chart", "x-ui-title": "Monthly Revenue Trend", "x-ui-data": { "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"], "datasets": [ { "label": "2024 Revenue", "data": [65, 75, 72, 88, 95, 102] }, { "label": "2023 Revenue", "data": [60, 68, 70, 82, 90, 98] } ] } }, "regional_breakdown": { "x-ui-type": "pie-chart", "x-ui-title": "Sales by Region", "x-ui-data": { "labels": ["North", "South", "East", "West"], "datasets": [ { "data": [25, 20, 35, 20] } ] } }, "conversion_funnel": { "x-ui-type": "funnel-chart", "x-ui-title": "Sales Funnel", "x-ui-data": { "labels": ["Leads", "Prospects", "Quotes", "Customers"], "datasets": [ { "data": [1000, 450, 200, 85] } ] } } } }

Example 3: Large Data Table with TanStack

- name: ApproveExpenses type: HumanTask ui: schema: urn:cascade:schema:expense_approvals target: tanstack config: selectable: true bulk_actions: - action: approve_all label: "Approve Selected" - action: reject_all label: "Reject Selected" timeout: 4h next: ProcessApprovals

Expense table schema:

{ "title": "Pending Expense Reports", "type": "array", "items": { "type": "object", "properties": { "expense_id": { "type": "string" }, "submitter": { "type": "string" }, "amount": { "type": "number" }, "category": { "type": "string" }, "date": { "type": "string", "format": "date" }, "status": { "type": "string" } } }, "x-ui-columns": [ { "id": "submitter", "header": "Employee", "width": "15%" }, { "id": "amount", "header": "Amount", "type": "number", "format": "currency", "width": "12%" }, { "id": "category", "header": "Category", "width": "15%" }, { "id": "date", "header": "Date", "type": "date", "width": "12%" }, { "id": "status", "header": "Status", "type": "badge", "width": "10%" } ], "x-ui-filters": [ { "id": "category", "type": "multi-select" }, { "id": "amount", "type": "range" }, { "id": "date", "type": "date-range" } ] }

Performance Optimization

Caching Strategy

ScenarioLatencyStrategy
Cold (new schema)127msFetch, parse, render
Cache hit (same schema)42msUse cached parsed schema
Context injection+10msInterpolate variables
Total (typical)52msNegligible to users

Tips for Large Forms

DO:

  • Split into multi-step forms
  • Use lazy loading for large datasets
  • Cache schemas in browser
  • Pre-populate from context
  • Use virtualization for large tables

DON’T:

  • Render 1000+ fields at once
  • Fetch all data upfront
  • Inline large data
  • Disable pagination

Troubleshooting

Schema Validation Errors

Error: Invalid JSON Schema: missing $schema

Solution: Add schema header:

{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", ... }

Fields Not Showing

Symptom: Form renders but fields missing

Causes:

  • additionalProperties: false hiding fields
  • Fields not in properties dict
  • Schema reference ($ref) not resolved

Debug:

cascade schema inspect urn:cascade:schema:myschema

Performance Issues

Symptom: Form takes >1s to render

Solutions:

  • Check schema size: cascade schema analyze
  • Enable caching: Add to config
  • Reduce fields: Use multi-step forms
  • Profile: cascade trace ui-render

Best Practices

DO:

  • Use semantic property names
  • Add descriptions and defaults
  • Include validation rules (min, max, pattern)
  • Pre-populate when possible
  • Use computed fields for derived values
  • Enable field-level validation

DON’T:

  • Store large data in schemas
  • Use overly complex conditionals
  • Nest more than 3 levels
  • Load entire datasets upfront
  • Omit accessibility attributes

Next Steps

Ready to build forms?First Workflow Tutorial

Need JSON Schema help?Schema Reference

Want advanced customization?UI Customization Guide

Performance troubleshooting?Performance Guide


Updated: October 29, 2025
Version: 2.0
JSON Schema Version: Draft 7
Production-Ready: Yes

Last updated on