Skip to content

Declarative UI & Widget Tree

ZKite applications are built declaratively. You do not manually instantiate Android View objects or manipulate DOM elements. Instead, you compose a Widget Tree that describes what the screen should look like for a given application state.

Your root application component returns a hierarchy of widgets:

from zkite import Column, Row, Text, Icon, Button
def Screen():
return Column(
"flex-1 p-4 bg-slate-950",
Row(
"w-full items-center justify-between mb-4",
Text("text-xl font-bold text-white", "Dashboard"),
Icon("text-white text-lg", name="settings"),
),
Text("text-slate-400 mb-6", "Welcome back!"),
Button(
"w-full py-3 bg-emerald-500 rounded-xl",
Text("text-white font-semibold text-center", "Start New Task"),
on_tap=handle_start_task,
),
)

Notice how widgets in ZKite are constructed:

When state changes and your component re-runs, ZKite compares the new widget tree with the existing tree to update native views efficiently.

For dynamic or reordered items (such as items inside a list or fields with user input), assign a stable key:

for item in items:
Row("p-3 border-b border-slate-800",
Text("text-white", item.name),
key=f"item-{item.id}"
)

A stable key ensures that Android preserves internal state (such as focused text fields, scroll offsets, and active animations) rather than destroying and recreating native views.