Skip to content

Grids & Layout

Whether the host is a terminal or a browser, layout in [xnano]{data-preview} is a 2D grid of cells.

A BaseGrid is a resizable, focusable, rectangular region. Fields on the grid mark smaller regions that can:

  • Render content (text, components, nested grids)
  • Hold typed state (including state=True fields that never paint)
  • Handle input through @on_* hooks
The z axis

Along with x and y, fields and grids accept a z value. For each cell, the highest z wins. Use it for overlays and stacked panels.

Creating a Grid

BaseGrid is declared like a Pydantic model: subclass it and annotate slots with Field.

Interactive

This code block runs in the browser via Pyodide.

Try editing the code!
  • Change direction between "vertical" and "horizontal".
  • Change the title field's default=.

Editor (session: default)Run
from xnano import BaseGrid, Field, render

class App(BaseGrid, direction="vertical"):
    title: str = Field(default="My App", border="rounded")
    body: str = Field(default="Hello")
    name: str = Field(default="Hammad", state=True)

render(App())
OutputClear

Creating a Grid
from xnano import BaseGrid, Field

class App(BaseGrid, direction="vertical"): # (1)!
    title: str = Field(default="My App", border="rounded") # (2)!
    body: str = Field(default="Hello")
    name: str = Field(default="Hammad", state=True) # (3)!
  1. Grid settings go on the class header (direction, gap, border, …) or on a grid_settings attribute.
  2. Field(...) sizes and styles the slot, and holds the value.
  3. state=True keeps the value off the paint path.

Grid Settings

Settings that apply to the whole grid — layout direction, gap, outer frame — are separate from individual fields.

Interactive

This code block runs in the browser via Pyodide.

Try editing the code!
  • Change gap (e.g. 0 or 2).
  • Change direction to "vertical".

Editor (session: default)Run
from xnano import BaseGrid, Field, render

class Dashboard(BaseGrid, direction="horizontal", gap=1, border="rounded", title=" Dashboard "):
    left: str = Field(default="Left", width="1fr")
    right: str = Field(default="Right", width="1fr")

render(Dashboard())
OutputClear

Grid Settings
from xnano import BaseGrid, Field

class Dashboard(BaseGrid, direction="horizontal", gap=1, border="rounded", title=" Dashboard "): # (1)!
    left: str = Field(default="Left", width="1fr")
    right: str = Field(default="Right", width="1fr")
  1. Everything after BaseGrid in the class header is a grid setting.

The same settings can be declared on grid_settings:

class Dashboard(BaseGrid, direction="horizontal", gap=1, border="rounded"):
    ...
from xnano import BaseGrid, GridSettings

class Dashboard(BaseGrid):
    grid_settings = GridSettings(
        direction="horizontal",
        gap=1,
        border="rounded",
    )
    ...

Both forms merge if used together; a subclass's grid_settings wins over inherited class-header values.

direction and gap are the common ones. Color, borders, padding, title, and modifiers use the same vocabulary as Field, applied to the grid's outer frame. See GridSettings.

Nested Grids

A field value can be another BaseGrid. Nested grids are ordinary content.

Nested Grids
from xnano import BaseGrid, Field

class Sidebar(BaseGrid, direction="vertical"):
    home: str = Field(default="Home", height=1)
    search: str = Field(default="Search", height=1)

class App(BaseGrid, direction="horizontal"):
    sidebar: Sidebar = Field(default_factory=Sidebar, width="1/3")
    content: str = Field(default="…", width="2fr")

overlay=True on a field takes that field out of flow and centers it over the grid (with z for stacking). See Getting Started for a full popup example.

Useful grid methods:

Method Role
grid_render / grid_render_* Refresh fields each frame (or per size tier)
grid_set_field(name, ...) Mutate a field value or layout metadata at runtime
grid_effect(...) Animate field areas — Effects

Displaying Content

Grids do not know which host will run them. The same instance (or class) can go to a Terminal or a Web host.

Terminal

render()
from xnano import render

render(App()) # (1)!
  1. One-shot paint, similar to print with layout and style.
Terminal
from xnano import Terminal

Terminal().run(App()) # (1)!
  1. Live session: frames and events until exit.

Web

Web
from xnano import Web

Web().run(App(), port=8000)

HTTP request hooks on grids are a separate surface — see Requests.

API

BaseGrid · GridSettings · Field · Terminal · Web