ui
Generated by tinox doc
Tinox-UI -- a server-driven web UI framework (Vaadin/Phoenix LiveView-style): write your whole UI as a Tinox component tree running on the server, a thin generic JS client renders it and ships events back over a persistent WebSocket.
| Module | Version | Group |
|---|---|---|
json | 1.0.0 | tinox.core |
http_server | 1.0.1 | tinox.core |
websocket | 1.0.2 | tinox.core |
Annotated counter
import tinox.core.ui;
import tinox.core.websocket;
import tinox.core.http_server;
// Annotation-driven: no HttpServer/WsServer wiring anywhere in the
// program -- @TinoxUIApp generates the HTTP shell/client-JS server and
// the WebSocket accept loop, calling the class's own @View method to
// build/rebuild the component tree (full-resend rendering, automatic
// re-render after every event).
@TinoxUIApp(8080, 8081)
class CounterApp
{
var clicks: Int64;
@View
fn render() -> Component
{
let app: CounterApp = this;
return Component::vbox([
Component::label("Clicks: " + this.clicks.toString()),
Component::button("Click me", fn(v: String) { app.clicks = app.clicks + 1; })
]);
}
}
Annotated counter entry point
import CounterApp;
// Every Tinox program still needs its own class Main as the mandatory
// entry point (since 2026-08-09) -- @TinoxUIApp's generated HTTP/WS
// servers spawn and run alongside it on their own threads, they don't
// replace it. This is the required sibling file for the annotated app
// above.
class Main
{
fnc main() -> Int32
{
return 0;
}
}
Widgets and routing
import tinox.core.ui;
import tinox.core.websocket;
import tinox.core.http_server;
// A wider tour of the widget library plus client-side routing:
// Component::link(text, path, onNavigate) reports its target path back
// through the same onEvent/dispatchEvent pipeline every other
// interactive widget uses -- an app switches views by keeping its own
// current-view state (a plain instance field) and branching inside its
// own @View method, no separate routing annotation needed.
@TinoxUIApp(8080, 8081)
class ShowcaseApp
{
var isAbout: Bool;
var quantity: Float64;
@View
fn render() -> Component
{
let app: ShowcaseApp = this;
let nav: Component = Component::hbox([
Component::link("Home", "/", fn(p: String) { app.isAbout = false; }),
Component::link("About", "/about", fn(p: String) { app.isAbout = true; })
]);
if this.isAbout
{
return Component::vbox([nav, Component::heading("About", 1)]);
}
return Component::vbox([
nav,
Component::heading("Widgets", 1),
Component::numberField(this.quantity, fn(v: Float64) { app.quantity = v; }),
Component::progressBar(this.quantity)
]);
}
}
Widgets and routing entry point
import ShowcaseApp;
class Main
{
fnc main() -> Int32
{
return 0;
}
}
class Assets
Methods
fnc shellHtml(wsPort: Int64) → String
fnc shellHtmlTemplate() → String
fnc clientJs() → String
@JsonSerializableclass Component
Fields
id | String | |
type | String | |
text | String | |
props | Map<String, String> | |
children | List<Component> | |
visible | Bool | |
@DoNotSerializeonEvent | fn(String) -> Nothing |
Methods
fnc inert(value: String) → Nothing
fnc none() → Component
fnc label(text: String) → Component
fnc button(text: String, onClick: fn(String) -> Nothing) → Component
fnc textField(value: String, onChange: fn(String) -> Nothing) → Component
fnc checkbox(checked: Bool, onChange: fn(String) -> Nothing) → Component
fnc textArea(value: String, onChange: fn(String) -> Nothing) → Component
fnc numberField(value: Float64, onChange: fn(Float64) -> Nothing) → Component
fnc intField(value: Int64, onChange: fn(Int64) -> Nothing) → Component
fnc heading(text: String, level: Int64) → Component
fnc image(src: String, alt: String) → Component
fnc spacer() → Component
fnc progressBar(value: Float64) → Component
fnc dropdown(options: List<String>, selected: String, onChange: fn(String) -> Nothing) → Component
fnc link(text: String, path: String, onNavigate: fn(String) -> Nothing) → Component
fnc datePicker(value: String, onChange: fn(String) -> Nothing) → Component
fnc radioGroup(options: List<String>, selected: String, onChange: fn(String) -> Nothing) → Component
fnc fileUpload(onChange: fn(String) -> Nothing) → Component
fnc tabs(labels: List<String>, activeIndex: Int64, content: Component, onTabChange: fn(String) -> Nothing) → Component
fnc dialog(title: String, content: Component, open: Bool, onClose: fn(String) -> Nothing) → Component
fnc notification(message: String, kind: String) → Component
fnc accordionSection(header: String, content: Component, expanded: Bool) → Component
fnc accordion(sections: List<Component>) → Component
fnc gridRow(cells: List<Component>) → Component
fnc gridCell(text: String, isHeader: Bool) → Component
fnc vbox(children: List<Component>) → Component
fnc hbox(children: List<Component>) → Component
fnc html(rawHtml: String) → Component
fn withStyle(style: String) → Component
class DataGrid<T>
Methods
fnc of(items: List<T>, columns: List<GridColumn<T>>) → Component
class GridColumn<T>
Fields
header | String | |
accessor | fn(T) -> String |
Methods
fnc of(header: String, accessor: fn(T) -> String) → GridColumn<T>
@JsonSerializableclass TinoxUIPatchMessage
Fields
kind | String | |
ops | List<TinoxUIPatchOp> |
@JsonSerializableclass TinoxUIPatchOp
Fields
op | String | |
id | String | |
text | String | |
props | Map<String, String> | |
node | Component | |
parentId | String | |
index | Int64 |
class TinoxUIRuntime
Methods
fnc buildHandlers(root: Component) → Map<String, fn(String) -> Nothing>
fnc assignIds(node: Component, handlers: Map<String, fn(String) -> Nothing>, counter: List<Int64>) → Nothing
fnc sendInit(conn: Int64, root: Component) → Nothing
fnc sendUpdate(conn: Int64, root: Component) → Nothing
fnc diff(old: Component, new_: Component, counter: List<Int64>, ops: List<TinoxUIPatchOp>) → Nothing
fnc assignIdsOnly(node: Component, counter: List<Int64>) → Nothing
fnc collectHandlers(node: Component, handlers: Map<String, fn(String) -> Nothing>) → Nothing
fnc propsEqual(a: Map<String, String>, b: Map<String, String>) → Bool
fnc sendPatch(conn: Int64, ops: List<TinoxUIPatchOp>) → Nothing
fnc dispatchEvent(handlers: Map<String, fn(String) -> Nothing>, msg: String) → Nothing