Pages
Pages define the XML UI returned by SDK page handlers. The root page covers the runtime concepts shared by every element: state, queries, actions, loops, conditions, translations, expressions, bindings, and invalidation.
XML page references live in the SDK pages section: expressions, layout elements and component elements.
Folder conventions
SDK applications use conventional folders under src. LongLink registers these folders at startup when they exist, so pages and translations can be added without writing Python route code.
src/pagescontains XML page files. Files are registered recursively under/pages, sosrc/pages/admin/users.xmlis served as/pages/admin/users.xml, listed in/pages.json, and available in the browser at/admin/users.src/i18ncontains locale catalogs. JSON files are served under/i18n, sosrc/i18n/en.jsonis available as/i18n/en.jsonfor the XML runtime.
src/pages/index.xmldashboard.xmlissues.xmlissues/[issue].xmladmin/users.xmli18n/en.json
Dynamic Pages
Dynamic browser pages come from file names. Use square brackets around one path segment to declare a route parameter; the SDK keeps serving the XML file from its literal /pages path and exposes the derived browser route through /pages.json.
src/pages/index.xml: browser route/.src/pages/issues.xml: browser route/issues.src/pages/issues/[issue].xml: browser route/issues/:issue.src/pages/issues/[issue]/comments.xml: browser route/issues/:issue/comments.
Dynamic pages inherit their navigation tab from the first static segment, so /issues and /issues/123 keep the same Issues tab active. Matched parameters are available as params in XML expressions.
xml<longlink><Query id="issue" path="/api/issues/${params.issue}" /><Heading level="1" i18n="issues.detailTitle" /><Text i18n="issues.detailSummary" values="${{ title: issue.title }}" /></longlink>
LongLink Page and I18n Mounts
LongLink() registers XML pages and translation catalogs from conventional source folders. The scaffolded application uses the defaults through LongLink(), which is equivalent to mounting pages from src/pages at /pages and translations from src/i18n at /i18n.
pythonfrom longlink import LongLinkapp = LongLink(pages="/pages",i18n="/i18n",)
Change the paths when your application uses different source folders. For example, pages="/screens" registers XML files from src/screens under /screens. Set pages=None or i18n=None when the application should not use the SDK-managed page or translation mounts.
Page Metadata
The root longlink element can define page tab metadata with name and icon. During page registration, the SDK reads these values and includes them in /pages.json so the web runtime can render application navigation consistently.
name: readable label shown for the page tab.icon: Lucide icon slug shown next to the page tab label.
xml<longlink name="Orders" icon="clipboard-list"><Heading level="1" i18n="orders.title" /><Text as="p" i18n="orders.description" /></longlink>
Translations
XML pages keep visible copy in translation catalogs through the i18n attribute. After adding or renaming translation keys in page XML, run the generator from the app root to refresh src/i18n/en.json while preserving existing translated values.
bashlonglink translations generate
State
Declares local reactive page state before rendering. Descendant controls can read and write the state through XML value bindings.
Parameters
- id: required literal state name.
- Any additional attribute becomes an initial state field. JSON values are parsed when possible, otherwise the value is evaluated.
- State is setup-only, does not render, and cannot have children.
xml<State id="form" name="" active="true" /><FormLayout><TextInput i18n="customers.name" value="$form.name" isRequired="true" /><CheckboxInput i18n="customers.active" value="$form.active" /></FormLayout>
Query
Fetches JSON data for the page before rendering. The response is stored in the runtime context and can be used by expressions, loops, and bindings.
Parameters
- id: required literal query name.
- path: required request path, resolved relative to the current application base URL and evaluated against the XML runtime scope.
- Query is setup-only, does not render, and cannot have children.
xml<Query id="orders" path="/api/orders" /><For each="$orders.items" as="order"><Text i18n="orders.row" values="${{ number: order.number, status: order.status }}" /></For>
Action
Provides request behavior to a child Button and sends the mutation when that button is activated.
Parameters
- action: optional application-relative request path.
- method: optional HTTP method. Defaults to POST.
- json: optional expression payload sent as JSON.
- form: optional expression object sent as multipart form data instead of JSON.
- invalidate: optional expression resolving to setup ids to refresh.
xml<Action action="/api/orders/${order.id}/complete" invalidate="${['orders']}"><Button i18n="orders.complete" /></Action>
For
Repeats child XML for each item in an array. Every iteration gets a child scope with the item alias and an index value.
Parameters
- each: required expression that must resolve to an array.
- as: required local variable name for each item.
xml<For each="$orders.items" as="order"><Card><Heading level="3" i18n="orders.cardTitle" values="${{ index: index + 1, number: order.number }}" /><Badge i18n="orders.status" values="${{ status: order.status }}" /></Card></For>
if
Global conditional prop supported by rendered XML nodes. When the expression is falsy, the node and its children are skipped.
Parameters
- if: expression evaluated in the current XML runtime scope.
xml<Badge if="$order.blocked" variant="error" i18n="orders.blocked" />
i18n
Global translation prop used by text-bearing elements. The value is a literal dotted key into the active locale bundle, not an expression.
Parameters
- i18n: dotted translation key.
- count: optional expression used for plural translation entries.
- values: optional expression resolving to one object that fills
{{name}}placeholders.
xml<Heading level="1" i18n="orders.title" /><Text i18n="orders.count" count="${orders.items.length}" /><Button i18n="orders.assign" values="${{ user: assignee.name }}" />
Expressions
Expressions have a dedicated reference covering $ bindings, ${...} typed values, interpolation, supported operators, safe calls, and XML escaping.
Read the expressions reference before writing complex conditions or action payloads.
xml<TextInput label="Order name" value="$form.name" /><Text i18n="orders.summary" values="${{ name: form.name }}" count="${orders.items.length}" /><Button isDisabled="${form.saving || !form.name}" i18n="actions.save" />