Forms
The form namespace provides a declarative UI toolkit for building structured data-entry forms inside ZeyOS weblets. Layout containers and input controls render natively in the ZeyOS interface — no HTML or CSS required. The form namespace only works in weblets; using it in services, resources, or standalone zeysdk run produces no visible output.
When a form is submitted, each control's id attribute becomes a key in the entity's extended data (EXTDATA). Use $EXTDATA.fieldId to read previously submitted values on subsequent loads.
In this chapter
hboxandvbox— horizontal and vertical layout containersplaceholder— empty spacer elementtitle,description,link,image,rule— display elementstextbox— text input with 17 type variantscheckbox— two-state togglelistboxandlistitem— single and multi-select listsentitybox— ZeyOS entity record selector
Layout containers
hbox — Horizontal box
Arranges child form elements side by side in a row. The most common use is placing two or more fields on one line, or creating multi-column layouts with nested vbox containers. Accepts optional align, width, height, and padding attributes.
Full reference →
<hbox>
<textbox id="firstname" label="First Name" width="300" />
<textbox id="lastname" label="Last Name" width="300" />
</hbox>
Multi-column layout with vbox nesting:
<hbox>
<vbox width="50%">
<textbox id="company" label="Company" width="300" />
<textbox id="email" label="Email" type="email" width="300" />
</vbox>
<vbox width="50%">
<textbox id="phone" label="Phone" type="tel" width="300" />
<textbox id="website" label="Website" type="url" width="300" />
</vbox>
</hbox>
vbox — Vertical box
Stacks child form elements vertically. Use it inside an hbox to create columns, or standalone to control width and padding. Accepts optional align, width, height, and padding attributes.
Full reference →
<hbox>
<vbox width="25%">
<title>Locations</title>
<foreach var="config.locations" var_value="location">
<checkbox id="loc_$location" caption="$location">$location</checkbox>
</foreach>
</vbox>
<vbox width="25%">
<title>Departments</title>
<foreach var="config.departments" var_value="dept">
<checkbox id="dept_$dept" caption="$dept">$dept</checkbox>
</foreach>
</vbox>
<vbox width="25%">
<textbox id="date_from" label="From" type="date" width="200" />
</vbox>
<vbox width="25%">
<textbox id="date_to" label="To" type="date" width="200" />
</vbox>
</hbox>
placeholder — Empty placeholder
Reserves empty space in a layout. Use it to balance columns when one side of an hbox has fewer controls, or to insert spacing between sections. Accepts optional width and height attributes.
Full reference →
<hbox>
<textbox id="notes" type="multi" label="Additional Notes" />
<placeholder />
</hbox>
Display elements
title — Section title
Renders an emphasized heading that visually separates form sections.
Full reference →
<title>Contact Information</title>
<hbox>
<textbox id="email" label="Email" type="email" width="300" />
<textbox id="phone" label="Phone" type="tel" width="300" />
</hbox>
<rule />
<title>Address</title>
<textbox id="street" label="Street" width="400" />
<hbox>
<textbox id="zip" label="ZIP" width="100" />
<textbox id="city" label="City" width="300" />
</hbox>
description — Labeled description
Displays read-only text attached to a label. Use it to show computed values, status information, or messages that the user cannot edit. Accepts an optional label attribute.
Full reference →
<description label="Created">
<date:format format="d.m.Y">$EXTDATA.created</date:format>
</description>
<description label="Created by">$EXTDATA.creator_name</description>
<description label="Status">$EXTDATA.status</description>
Summary row with computed values:
<hbox>
<description label="Total Net">$formatNum($totalNet)</description>
<description label="Total Gross">$formatNum($totalGross)</description>
<description label="Balance">$formatNum($balance)</description>
</hbox>
link — Hyperlink
Renders a clickable hyperlink with a label. The content is the display text, and the url attribute sets the target.
Full reference →
<link label="Customer Portal" url="./remotecall/portal/$ID">Open Portal</link>
<link label="Documentation" url="https://docs.example.com">View Docs</link>
image — Image
Renders an image with optional label, caption, and clickable url. The content provides the image source path or URL.
Full reference →
rule — Horizontal rule
Renders a horizontal divider line between form sections. Accepts an optional width attribute.
Full reference →
<title>General</title>
<textbox id="name" label="Name" width="300" />
<rule />
<title>Details</title>
<textbox id="description" label="Description" type="multi" height="150" />
Input controls
textbox — Text input
The most versatile form control. Renders an editable input whose behavior changes based on the type attribute — from single-line text to a rich HTML editor, from a date picker to a currency input. Key attributes: id, label, type, width, placeholder, required, readonly, disabled, caption, pattern.
Full reference →
Input types
| Type | Description | Extra attributes |
|---|---|---|
single | Single-line text input | caption, pattern |
multi | Multi-line text area | height |
html | Rich HTML editor | height |
email | Email address input with validation | caption, pattern |
url | URL input with validation | caption, pattern |
tel | Telephone number input | caption, pattern |
password | Password input (masked characters) | caption, pattern |
num | Numeric input | caption |
money | Monetary value input | caption |
price | Price input (general) | caption |
pricebilling | Price input (billing context) | caption |
priceprocurement | Price input (procurement context) | caption |
priceproduction | Price input (production context) | caption |
country | Country code selector (ISO 3166-1 alpha-2) | caption |
currency | Currency code selector (ISO 4217) | caption |
unit | Unit code selector (UN/CEFACT Recommendation 20) | caption |
date | Date picker | caption |
datetime | Date and time picker | caption |
Example — Contact form with mixed types
<title>Contact Details</title>
<hbox>
<vbox width="50%">
<textbox id="name" label="Full Name" width="300" required="true" />
<textbox id="email" label="Email" type="email" width="300" required="true" />
<textbox id="phone" label="Phone" type="tel" width="300" />
</vbox>
<vbox width="50%">
<textbox id="website" label="Website" type="url" width="300" />
<textbox id="country" label="Country" type="country" width="200" />
<textbox id="revenue" label="Annual Revenue" type="money" width="200" caption="€" />
</vbox>
</hbox>
<rule />
<textbox id="notes" label="Notes" type="multi" height="200" />
Example — Date range filter
<hbox>
<textbox id="date_from" label="From" type="date" width="200" />
<textbox id="date_to" label="To" type="date" width="200" />
</hbox>
Example — Numeric inputs with loop
<for var="quarter" from="1" to="4">
<hbox>
<textbox id="revenue_q$quarter$" type="money" width="200"
label="Revenue Q$quarter" caption="€" />
<textbox id="margin_q$quarter$" type="num" width="100"
label="Margin Q$quarter" caption="%" />
</hbox>
</for>
Example — Readonly computed field
<textbox id="total" label="Total" type="num" width="200"
readonly="true">$($subtotal * (1 + $taxrate / 100))</textbox>
checkbox — Check box
Renders a two-state toggle. The content defines the value submitted when checked. When unchecked, the field is absent from EXTDATA (test with <if value1="$EXTDATA.myCheckbox" func="!=">). Key attributes: id, label, caption, selected, disabled.
Full reference →
Example — Simple option
<checkbox id="newsletter" label="Subscribe" caption="Receive newsletter">1</checkbox>
Example — Dynamic checkbox group
A common pattern is generating checkboxes from data, using unique IDs:
<title>Services</title>
<foreach var="services" var_value="service">
<replace pattern="[^A-Za-z0-9]" var="safeId">$service</replace>
<checkbox id="svc_$safeId$" caption="$service">$service</checkbox>
</foreach>
Example — Approval workflow
<checkbox id="approved" caption="I approve this document"
disabled="$readonly">$session.name||$DATENOW</checkbox>
When checked, the value stored is a composite string like "John Doe||2026-02-08", recording both who approved and when.
listbox — Selection list
Renders a dropdown (type="single") or a scrollable checkbox list (type="multi"). Items are defined with <listitem> children. For multi-select, selected values are joined with the delimiter (default ", ") into a single string — use <split> or <decode:csv> to parse them back. Key attributes: id, label, type, width, required, disabled, caption (placeholder for single), height (for multi), delimiter (for multi).
Full reference →
listitem — List item
Defines a single option within a <listbox>. The content is the submitted value; the caption attribute is the display text (defaults to the value). Use selected="true" to pre-select.
Full reference →
Example — Static dropdown
<listbox id="priority" label="Priority" width="200">
<listitem caption="Low">1</listitem>
<listitem caption="Medium" selected="true">2</listitem>
<listitem caption="High">3</listitem>
<listitem caption="Critical">4</listitem>
</listbox>
Example — Dynamic dropdown from database
<db:select var_result="users" type="assoc">
<db:fields>
<db:field>name</db:field>
<db:field>firstname</db:field>
<db:field>lastname</db:field>
</db:fields>
<db:table>users</db:table>
</db:select>
<listbox id="assignee" label="Assignee" width="300" caption="Select a user...">
<foreach var="users" var_value="user">
<listitem caption="$user.firstname $user.lastname">$user.name</listitem>
</foreach>
</listbox>
Example — Multi-select with height
<listbox id="categories" type="multi" label="Categories"
height="200" delimiter=",">
<foreach var="settings.categories" var_value="cat">
<listitem>$cat</listitem>
</foreach>
</listbox>
Example — Percentage selector with loop
<listbox id="probability" label="Probability" width="150">
<for var="pct" from="0" to="100" step="10">
<listitem caption="$pct %">$($pct / 100)</listitem>
</for>
</listbox>
entitybox — Entity selector
A specialized selector for choosing a ZeyOS entity record (contact, account, ticket, etc.) by ID, with auto-complete search. Use the tag attribute to filter results. Key attributes: id, entity, tag, label, caption, placeholder, width, required, disabled.
Full reference →
Example — Contact and account selectors
<hbox>
<entitybox id="contact_id" entity="contacts" label="Contact"
width="300" required="true" />
<entitybox id="account_id" entity="accounts" label="Company"
width="300" placeholder="Search company..." />
</hbox>
Example — Filtered entity selection
<entitybox entity="contacts" id="vendor_id" tag="Vendor"
label="Vendor" width="300" required="true" />
Only contacts tagged "Vendor" appear in the search results.
Example — Dynamic entity type
<listbox id="entityType" label="Entity Type" width="200">
<listitem caption="Projects">projects</listitem>
<listitem caption="Tickets">tickets</listitem>
<listitem caption="Transactions">transactions</listitem>
</listbox>
<if value1="$EXTDATA.entityType" func="!=">
<entitybox entity="$EXTDATA.entityType" id="entityIndex"
label="Record" width="300" />
</if>
Common layout patterns
Two-column form
<hbox>
<vbox width="50%">
<textbox id="firstname" label="First Name" width="280" />
<textbox id="email" label="Email" type="email" width="280" />
<textbox id="phone" label="Phone" type="tel" width="280" />
</vbox>
<vbox width="50%">
<textbox id="lastname" label="Last Name" width="280" />
<textbox id="company" label="Company" width="280" />
<textbox id="position" label="Position" width="280" />
</vbox>
</hbox>
Sectioned form with dividers
<title>General Information</title>
<hbox>
<textbox id="name" label="Name" width="300" required="true" />
<listbox id="status" label="Status" width="200">
<listitem>Active</listitem>
<listitem>Inactive</listitem>
</listbox>
</hbox>
<rule />
<title>Financial Details</title>
<hbox>
<textbox id="budget" label="Budget" type="money" width="200" caption="€" />
<textbox id="currency" label="Currency" type="currency" width="150" />
</hbox>
<rule />
<title>Notes</title>
<textbox id="notes" label="Internal Notes" type="multi" height="150" />
Conditional form sections
<if value1="$EXTDATA.approved" func="!=">
<!-- Already approved — show read-only summary -->
<description label="Approved by">$EXTDATA.approved_by</description>
<description label="Approved on">
<date:format format="d.m.Y">$EXTDATA.approved_date</date:format>
</description>
<else>
<!-- Not yet approved — show approval controls -->
<checkbox id="approve" caption="I approve this request">1</checkbox>
<textbox id="approve_comment" label="Comment" type="multi" height="100" />
</else>
</if>
Data-driven form generation
Generate form controls dynamically from configuration or database queries:
<foreach var="APPSETTINGS.customFields" var_key="fieldId" var_value="field">
<switch value1="$field.type">
<case value="text">
<textbox id="cf_$fieldId" label="$field.label" width="300" />
</case>
<case value="number">
<textbox id="cf_$fieldId" label="$field.label" type="num"
width="200" caption="$field.unit" />
</case>
<case value="select">
<listbox id="cf_$fieldId" label="$field.label" width="300">
<foreach var="field.options" var_value="opt">
<listitem>$opt</listitem>
</foreach>
</listbox>
</case>
<case value="bool">
<checkbox id="cf_$fieldId" caption="$field.label">1</checkbox>
</case>
</switch>
</foreach>
Complete weblet example
A realistic weblet form for contract management, combining all form elements:
<title>Contract Details</title>
<hbox>
<vbox width="50%">
<entitybox id="contact_id" entity="contacts" label="Contact"
width="300" required="true" />
<entitybox id="account_id" entity="accounts" label="Company"
width="300" />
<listbox id="contract_type" label="Type" width="300" required="true">
<listitem caption="Service Agreement">service</listitem>
<listitem caption="Maintenance Contract">maintenance</listitem>
<listitem caption="Consulting">consulting</listitem>
</listbox>
</vbox>
<vbox width="50%">
<textbox id="contract_num" label="Contract No." width="300"
readonly="true">$EXTDATA.contract_num</textbox>
<textbox id="start_date" label="Start Date" type="date"
width="200" required="true" />
<textbox id="end_date" label="End Date" type="date" width="200" />
</vbox>
</hbox>
<rule />
<title>Financial</title>
<hbox>
<textbox id="value" label="Contract Value" type="money"
width="200" caption="€" />
<textbox id="currency" label="Currency" type="currency" width="150" />
<listbox id="billing_cycle" label="Billing Cycle" width="200">
<listitem>Monthly</listitem>
<listitem>Quarterly</listitem>
<listitem>Annually</listitem>
</listbox>
</hbox>
<rule />
<title>Services</title>
<listbox id="services" type="multi" label="Included Services"
height="150" delimiter=",">
<foreach var="APPSETTINGS.serviceOptions" var_value="svc">
<listitem>$svc</listitem>
</foreach>
</listbox>
<rule />
<title>Notes</title>
<textbox id="internal_notes" label="Internal Notes" type="multi"
height="150" />
<hbox>
<checkbox id="auto_renew" caption="Auto-renew contract">1</checkbox>
<checkbox id="notify_expiry" caption="Notify before expiry"
selected="true">1</checkbox>
</hbox>
<rule />
<if value1="$EXTDATA.approved">
<description label="Approved by">$EXTDATA.approved_by</description>
<description label="Date">
<date:format format="d.m.Y H:i">$EXTDATA.approved_date</date:format>
</description>
<else>
<description label="Status">Pending approval</description>
</else>
</if>