<- Back to Complex Components

Purpose

Descriptions renders a single object as a two-column key/value table. Use it for account profiles, order snapshots, audit metadata, configuration summaries, and any detail view where fields should be shown with stable labels and formatted values.

The component is model-driven: model declares which fields to show and how to label or format them; data supplies the object values.

Constructor

Descriptions(
    id: str,
    model: list[dict[str, Any]] | None = None,
    data: dict[str, Any] | None = None,
    key_header: str = "Property",
    value_header: str = "Value",
    borders: bool = True,
)

Properties

Property Type Default Description
model list[dict] [] Field definitions rendered in order.
data dict {} Object read by each model field.
key_header str Property Header for the label column.
value_header str Value Header for the value column.
borders bool True Enables table border/grid styling.

Model Fields

Field Type Description
field str Key read from data. Required for a row to render.
label str Label shown in the left column.
header str Alternate label key used when label is not present.
type str Value coercion: str, bool, int, float, date, datetime.
format str Numeric or date formatting.
transform str Value transform such as title, upper, truncate\|36, or join_list\|, \|upper.
placeholder str Text shown when the value is missing.

When model is empty, the component builds rows from the keys present in data.

Examples

from democrai.sdk.client import active_sdk as sdk
from democrai.sdk.ui import bound

model = [
    {"field": "full_name", "label": "Full name", "type": "str"},
    {"field": "role", "label": "Role", "type": "str", "transform": "title"},
    {"field": "active", "label": "Active", "type": "bool"},
    {"field": "login_count", "label": "Logins", "type": "int"},
    {"field": "credit", "label": "Credit", "type": "float", "format": ".2f"},
    {"field": "signup_at", "label": "Signup date", "type": "datetime", "format": "%d/%m/%Y %H:%M"},
    {"field": "tags", "label": "Tags", "transform": "join_list|, |upper", "placeholder": "No tags"},
    {"field": "notes", "label": "Notes", "transform": "truncate|36", "placeholder": "No notes"},
    {"field": "missing", "label": "Missing value", "placeholder": "Not provided"},
]

data = {
    "full_name": "Lina Bianchi",
    "role": "platform admin",
    "active": True,
    "login_count": 42,
    "credit": 1234.5,
    "signup_at": "2026-03-21T09:30:00",
    "tags": ["owner", "billing", "security"],
    "notes": "Primary account owner with elevated operational permissions.",
}

details = sdk.ui.Descriptions(
    "details_static",
    model=model,
    data=data,
    key_header="Property",
    value_header="Value",
    borders=True,
)
details.set_show_if({
    "conditions": [
        {
            "left": bound.store("/components_test/descriptions/show", scope="page", default=True),
            "op": "==",
            "right": True,
        }
    ]
})
details.set_hide_if({
    "conditions": [
        {
            "left": bound.store("/components_test/descriptions/hide", scope="page", default=False),
            "op": "==",
            "right": True,
        }
    ]
})
details.set_required_permissions(["components.complex.view"])

Fallback Model

When model is empty, Descriptions creates one row per key in data.

sdk.ui.Descriptions(
    "details_fallback",
    model=[],
    data={
        "order_id": "ORD-2026-0042",
        "status": "shipped",
        "total": 289.9,
    },
    key_header="Auto field",
    value_header="Auto value",
    borders=False,
)

Binding and Updates

The demo binds model, data, key_header, value_header, and borders through both page store and surface data model. The same properties can be updated directly with propertyUpdate.

store_details = sdk.ui.Descriptions(
    "details_store",
    model=bound.store("/components_test/descriptions/model", scope="page", default=model),
    data=bound.store("/components_test/descriptions/data", scope="page", default=data),
    key_header=bound.store("/components_test/descriptions/key_header", scope="page", default="Property"),
    value_header=bound.store("/components_test/descriptions/value_header", scope="page", default="Value"),
    borders=bound.store("/components_test/descriptions/borders", scope="page", default=True),
)

data_details = sdk.ui.Descriptions(
    "details_data",
    model=bound.data("/components_test/descriptions_model/model", default=model),
    data=bound.data("/components_test/descriptions_model/data", default=data),
    key_header=bound.data("/components_test/descriptions_model/key_header", default="Property"),
    value_header=bound.data("/components_test/descriptions_model/value_header", default="Value"),
    borders=bound.data("/components_test/descriptions_model/borders", default=True),
)

live_details = sdk.ui.Descriptions("details_live", model=model, data=data)

Runtime updates must target the current surface:

surface_id = ctx["_surface_id"]

return sdk.effects.respond(
    sdk.effects.ui_messages([
        {
            "stateUpdate": {
                "scope": "page",
                "values": {
                    "/components_test/descriptions/model": next_model,
                    "/components_test/descriptions/data": next_data,
                    "/components_test/descriptions/key_header": "Field",
                    "/components_test/descriptions/value_header": "Current value",
                    "/components_test/descriptions/borders": False,
                },
            }
        },
        sdk.ui.Builder.build_data_model_update_payload(
            surface_id=surface_id,
            data={
                "components_test": {
                    "descriptions_model": {
                        "model": next_model,
                        "data": next_data,
                        "key_header": "Field",
                        "value_header": "Current value",
                        "borders": False,
                    }
                }
            },
        ),
    ]),
    sdk.effects.ui_property_update("details_live", "model", next_model, surface_id=surface_id),
    sdk.effects.ui_property_update("details_live", "data", next_data, surface_id=surface_id),
    sdk.effects.ui_property_update("details_live", "key_header", "Field", surface_id=surface_id),
    sdk.effects.ui_property_update("details_live", "value_header", "Current value", surface_id=surface_id),
    sdk.effects.ui_property_update("details_live", "borders", False, surface_id=surface_id),
)

Screenshots

Desktop:

Descriptions desktop

Web:

Descriptions web