S
supero.docs
Documentation/Building Your App/Dynamic UI

Dynamic UI

How Supero turns your schema into working tables, forms, and detail views automatically, and the real UI-schema mechanism you use to customize labels, view modes, per-field renderers, and conditional form fields.

Overview

Every entity you define gets a working admin UI for free: a searchable, sortable data table, create/edit forms with validation, and a detail view — all generated directly from your schema, with no frontend code to write or maintain.
The generation is live, not a one-time scaffold. Add a field to a schema and it shows up as a new form field, table column, and detail-view row the next time the app loads — because the UI is built at runtime from the same field list your schema serves through the CRUD API, not from a generated-once template.
json
{
  "name": "Product",
  "parent_type": "tenant",
  "attributes": [
    { "name": "price", "type": "float", "mandatory": true },
    { "name": "in_stock", "type": "boolean", "default-value": true },
    { "name": "status", "type": "string", "values": ["draft", "active", "discontinued"], "default-value": "draft" }
  ]
}
With nothing else declared, price becomes a number input and a numeric table column, in_stock becomes a checkbox, and status becomes a dropdown populated from values — covered in full in the next section. This page documents that default mapping, then the schema you author when you want more control than the default gives you.

Generated UI Components

Every schema you define is rendered through the same four building blocks in the generated admin console.
ComponentDriven ByBehavior
Data tableEvery field on the schemaSortable columns, a free-text search box that matches across every field, a status filter, and incremental "load more" paging.
Create / edit formFields + their required flagsA modal form scoped to the record type. Required fields block submission client-side; validation errors returned by the API are shown inline on the corresponding field.
Detail viewFields + related recordsA read-only layout of every field (image and file fields get their own hero/gallery treatment instead of a text row), plus any related child records you wire up.
Dashboard / KanbanNumeric fields, or an explicit board viewStat cards and simple charts computed by summing or averaging a numeric field across a schema’s records, and a drag-friendly board when a record type’s view is set to kanban.

ℹ️ Schema-driven

None of these four are separately configured components — they all read the same field list your schema exposes. Adding a field to the schema is enough to get a new column, a new form field, and a new detail row, with zero UI code.

Field Type to Default Control

Every field declares a type, and each type maps to a default control with no configuration required. For the full set of primitive types and the aliases accepted for each, see Schema Reference. Two composite forms also get their own control: a named type (a field whose type points at a separate type-kind schema, e.g. "type": "Address") and an inline enum (a string field with a values list).
Schema TypeWhat It DeclaresDefault Control
stringFree-form textText input (a field whose name contains "description" is rendered as a multi-line textarea automatically).
integerWhole numbersNumber input.
floatDecimal numbersNumber input with a decimal step — used for money, quantities, measurements.
booleanA true/false flagCheckbox.
Named type, e.g. "type": "Address"An embedded value structure defined as its own type-kind schemaA structured editor for that type — see Named & System Types below.
Enum: "type": "string", "values": [...]A fixed set of allowed valuesDropdown select, populated from the values list.
That table covers the types with a distinctive control, not the complete set of primitives. date and datetime fields get a date or date-time picker, and json fields get a structured key-value editor. Multi-value fields aren’t a separate type — set list: true (or IsList: true) on any field to store an array of values. And references between objects (references[]) are a distinct schema construct, not a field type. See Schema Reference for the full primitive list and for how references are declared and queried.

Named & System Types

Beyond the primitive types, a field’s type can name a type-kind schema you defined yourself, or one of the platform’s built-in system types. Several of the built-in system types map to a dedicated editor rather than falling back to a plain text input.
System TypeTypical UseEditor
AddressA street/city/postal-code structureaddress_editor
CurrencyA money amountcurrency_editor
PhoneNumberA phone numberphone_editor
EmailAn email addressemail_editor
GeoLocationA latitude/longitude pointgeo_point_editor
URLA web linkurl_editor
ImageA photo attachment (add list: true for a gallery)image_upload_editor
FileA document attachmentfile_upload_editor
A type-kind schema you define yourself — a composite structure like a custom LineItem or Address variant made of your own fields — is edited as structured, nested data rather than a single input; give it its own field editor (see Field Editors & Conditional Display below) if the generic structured editor isn’t what you want.

Customizing With UI Schemas

The default table, form, and detail view work with zero configuration. When you want a specific label, icon, section grouping, alternate view mode, or per-field display formatting, you author a second schema alongside your data schema — a UI schema — rather than annotating the data schema’s fields directly.
A UI schema is marked with its own schema_type, "ui". Like a type schema, it can use extends and it never gets CRUD endpoints or system fields of its own — it’s configuration for the runtime, not a record you create. In practice, you extend the platform’s base record UI (extends: "supero_ui:base_record_ui") and point it at your data schema with ui_for.
json
{
  "name": "order_admin_ui",
  "namespace": "shop",
  "schema_type": "ui",
  "parent_type": "tenant",
  "extends": "supero_ui:base_record_ui",
  "display_name": "Orders Admin UI",
  "attributes": [
    { "name": "ui_for", "type": "string", "default": "shop:order" },
    { "name": "surface", "type": "string", "default": "admin_panel" },
    { "name": "label", "type": "string", "default": "Orders" },
    { "name": "icon", "type": "string", "default": "shopping-bag" },
    { "name": "section", "type": "string", "default": "Sales" },
    { "name": "subtitle", "type": "string", "default": "All orders across every channel" },
    { "name": "default_view_mode", "type": "string", "default": "table" },
    { "name": "available_view_modes", "type": "string", "list": true, "default": ["table", "kanban", "detail"] },
    { "name": "header_actions", "type": "list", "default": [
      { "label": "+ New Order", "variant": "primary", "action_id": "create_record" }
    ]},
    { "name": "field_renderer__status", "type": "dict", "default": {
      "renderer": "status_pill",
      "config": { "color_map": { "pending": "amber", "shipped": "blue", "delivered": "green", "cancelled": "red" } }
    }},
    { "name": "field_renderer__total_amount", "type": "dict", "default": { "renderer": "currency" } },
    { "name": "detail_extras", "type": "list", "default": [
      { "child_schema": "line_item", "label": "Line Items", "limit": 20 }
    ]},
    { "name": "featured_fields", "type": "string", "list": true, "default-value": ["status", "total_amount", "customer_name"] }
  ]
}
KeyPurpose
ui_forThe qualified data-schema name this UI schema configures, e.g. "shop:order".
surfaceWhich surface this configuration applies to: admin_panel, live_app_authed, live_app_public, mobile_admin, or mobile_public.
label / icon / section / subtitleNavigation label, icon, grouping section, and a short description shown under the section title.
default_view_mode / available_view_modesWhich view loads by default, and which of the platform’s view modes (list, table, grid, detail, card, form, kanban, time_grid, calendar, seat_grid, map, cart, timeline, thread, metric_card, inline_edit, gallery, comparison) this record type supports.
header_actionsButtons shown above the list — each is a { label, variant, action_id } entry.
featured_fieldsAn ordered list of field names to surface prominently in cards and compact views.
detail_extrasRelated child schemas to show inline on the detail view, e.g. line items under an order.
field_renderer__<field_name>A display-time renderer override for one field: { "renderer": "...", "config": {...} }.

Field Editors & Conditional Display

Create/edit forms are customized one field at a time with a field editor entry. Anything you don’t override keeps its default control from the field-type table above.
KeyPurpose
editor_typeThe editor to use for this field, e.g. text, number, currency, date, boolean, enum, reference, address, image_upload, file_upload.
field_nameThe data-schema field this editor binds to.
label / tooltip / help_text / placeholderForm copy shown with the field.
required / readonly / autofocusOverrides the schema’s own required flag for this form context, locks the field, or focuses it on open.
icon / width_hintAn icon shown with the field, and how many columns it spans: narrow, normal, wide, or full.
depends_onSibling field names this editor re-evaluates against whenever one of them changes.
visible_when_field_equalsA condition — a JSON object mapping a sibling field name to the value it must equal — for this field to be shown at all.
json
{
  "editor_type": "date",
  "field_name": "delivery_date",
  "label": "Delivery date",
  "required": true,
  "depends_on": ["fulfillment_method"],
  "visible_when_field_equals": "{\"fulfillment_method\": \"shipping\"}"
}
In this example, the delivery_date field only appears once fulfillment_method is set to shipping — the same conditional-field idea a schema author needs, expressed through the real key the platform reads.

💡 Editor and renderer vocabulary

Common editor_type / renderer_type values: text, textarea, number, currency, percentage, boolean, date, time, email, phone, url, password, rating, color_picker, code, markdown, rich_text, json, key_value, tag_input, multi_select, enum, reference, address, geo_point, image_upload, and file_upload.

Surfaces & Visibility

Supero doesn’t generate one layout and reflow it for every context — it generates distinct surfaces, and a UI schema configures each independently for the same record type.
SurfaceWhat Renders There
admin_panelThe tenant admin console — full CRUD, every field, every record.
live_app_authedThe signed-in customer-facing app.
live_app_publicThe public, unauthenticated storefront or landing pages.
mobile_adminThe admin experience on mobile.
mobile_publicThe public/customer experience on mobile.
A separate customer_surface value controls how a record type shows up specifically in the signed-in customer app:
  • •browse — a read-only catalog tab.
  • •mine — an owner-scoped "My X" tab, create-enabled.
  • •shop — a catalog that feeds cart/checkout.
  • •hidden — never gets its own tab (picker-only entities, or back-office records like an internal coupon list).
If you omit customer_surface, the runtime classifies the record automatically based on whether tenant users can create it and whether it looks like a transactional entity — set it explicitly whenever the automatic guess isn’t what you want.

Next steps

Related pages:
  • •Schema Reference — the full fields[]/references[] format, primitive types, and how extends inheritance works.
  • •Anatomy of a Supero App — how schemas, seed data, and the generated UI fit together in a Supero app.
  • •Managing Data — creating, reading, updating, and deleting records through the API, SDKs, and admin console.