Skip to content

Markup & UI ​

AIVI markup is an expression language for UI trees. It looks XML-like, but it is part of the language surface and participates in ordinary AIVI binding rules.

Basic widgets ​

aivi
value view =
    <Window title="Greeting">
        <Box>
            <Label text="Hello" />
            <Label text="World" />
        </Box>
    </Window>

Capitalised tags name widgets or components. Attributes can be plain text or embedded expressions.

Binding expressions into attributes ​

aivi
value header = "Users"

value view =
    <Window title="Directory">
        <Label text={header} />
    </Window>

Anything inside {...} is an AIVI expression.

Typed widget properties ​

Widget attributes are schema-checked host properties, not an open CSS map. That means you bind ordinary expressions into the properties a widget exposes today.

aivi
type Bool -> Float
func previewOpacity =
 T|> 1.0
 F|> 0.25

value previewVisible = True

value view =
    <Window title="Preview">
        <Button label="Blue" animateOpacity={True} opacity={previewOpacity previewVisible} />
    </Window>

Button.opacity takes a Float and the GTK host clamps it into the 0.0 to 1.0 range. Button.animateOpacity takes a Bool and enables the built-in opacity transition class, so changes to opacity fade instead of snapping.

Because these are ordinary attributes, they can be driven by any signal-backed or source-backed expression. Arbitrary cssProps maps are not part of the current AIVI surface yet.

Conditional rendering with <show> ​

aivi
value isVisible = True

value view =
    <Window title="Status">
        <Box>
            <show when={isVisible} keepMounted={True}>
                <Label text="Visible" />
            </show>
        </Box>
    </Window>

<show> renders its body only when the condition holds.

when accepts Bool, and it also accepts the canonical truthy/falsy carriers Option, Result, and Validation (plus one outer Signal). That means request helpers such as usersResult.error or usersResult.success can plug straight into markup:

aivi
value fetchError = Some "offline"

value view =
    <Window title="Status">
        <show when={fetchError}>
            <Label text="Failed" />
        </show>
    </Window>

keepMounted stays a plain Bool.

Local bindings with <with> ​

aivi
type Item = {
    id: Int,
    title: Text
}

type Screen = Ready (List Item)

value screen =
    Ready [
        { id: 1, title: "Alpha" },
        { id: 2, title: "Beta" }
    ]

value view =
    <Window title="Items">
        <Box>
            <with value={screen} as={currentScreen}>
                <match on={currentScreen}>
                    <case pattern={Ready items}>
                        <each of={items} as={item} key={item.id}>
                            <Label text={item.title} />
                        </each>
                    </case>
                </match>
            </with>
        </Box>
    </Window>

<with> binds a value for the nested subtree.

Pattern matching with <match> ​

Markup has control nodes for the same pattern-oriented style used elsewhere in the language:

aivi
type Item = {
    id: Int,
    title: Text
}

type Screen =
  | Loading
  | Ready (List Item)
  | Failed Text

value screen =
    Ready [
        { id: 1, title: "Alpha" },
        { id: 2, title: "Beta" }
    ]

value view =
    <Window title="Items">
        <Box>
            <match on={screen}>
                <case pattern={Loading}>
                    <Label text="Loading..." />
                </case>
                <case pattern={Ready items}>
                    <each of={items} as={item} key={item.id}>
                        <Label text={item.title} />
                        <empty>
                            <Label text="No items" />
                        </empty>
                    </each>
                </case>
                <case pattern={Failed reason}>
                    <Label text={reason} />
                </case>
            </match>
        </Box>
    </Window>

Iteration with <each> ​

<each> renders one subtree per list item and can include an <empty> fallback when the list is empty.

Summary ​

ElementMeaning
<Label ... />A widget node
<fragment>...</fragment>Group children without an outer widget
<show when={...}>Conditional rendering
<with value={...} as={...}>Bind a value in markup
<match on={...}>Pattern-based rendering
<case pattern={...}>One match branch
<each of={...} as={...} key={...}>Iterate a list
<empty>Empty-list fallback inside <each>

See also: Building Snake — a complete application that uses every markup feature together


Widget catalog ​

This guide gives worked descriptions for the common widgets below. The final additional schema entries section lists other registered names; schema registration alone does not prove every native integration is complete.

Window ​

Top-level application window.

aivi
value view =
    <Window title="App" defaultWidth={800} defaultHeight={600}>
        <Window.titlebar>
            <HeaderBar />
        </Window.titlebar>
        <Label text="Hello, world!" />
    </Window>

Properties: title, defaultWidth, defaultHeight, resizable, modal, maximized, fullscreen, decorated, hideOnClose, visible, sensitive, opacity, hexpand, vexpand, halign, valign, widthRequest, heightRequest, marginStart, marginEnd, marginTop, marginBottom, tooltip, cssClasses, animateOpacity

  • maximized (Bool) — maximize or unmaximize the window
  • fullscreen (Bool) — enter or exit fullscreen mode
  • decorated (Bool) — show or hide window decorations (title bar, borders)
  • hideOnClose (Bool) — hide rather than destroy the window when closed

Events: onCloseRequest (Unit), onMaximize (Bool), onFullscreen (Bool)

  • onMaximize fires with True when maximized, False when restored
  • onFullscreen fires with True when entering fullscreen, False when leaving

HeaderBar ​

Title bar with optional start/end widget slots.

aivi
value view =
    <Window title="App">
        <Window.titlebar>
            <HeaderBar decorationLayout="close:">
                <HeaderBar.start>
                    <Button label="Back" />
                </HeaderBar.start>
                <HeaderBar.end>
                    <Button label="Menu" />
                </HeaderBar.end>
            </HeaderBar>
        </Window.titlebar>
        <Label text="Content" />
    </Window>

Properties: showTitleButtons, decorationLayout, centeringPolicy

  • decorationLayout (Text) — overrides the system button layout; format is "left-buttons:right-buttons" where tokens include close, maximize, minimize, icon (e.g. "close:", "menu:minimize,maximize,close")
  • centeringPolicy (Text) — controls title centering; "Loose" (default) centres the title when space allows, "Strict" always centres it even when the start/end widgets are asymmetric

Box ​

Linear layout container.

aivi
value view =
    <Window title="App">
        <Box orientation="Vertical" spacing={8}>
            <Label text="First" />
            <Label text="Second" />
        </Box>
    </Window>

Properties: orientation (Horizontal|Vertical), spacing, homogeneous

ScrolledWindow ​

Adds scrollbars to an inner widget.

aivi
value view =
    <Window title="App">
        <ScrolledWindow hexpand={True} vexpand={True}>
            <Box orientation="Vertical" spacing={4}>
                <Label text="Row 1" />
                <Label text="Row 2" />
            </Box>
        </ScrolledWindow>
    </Window>

Paned ​

Two-pane resizable splitter.

aivi
value view =
    <Window title="App">
        <Paned orientation="Horizontal" hexpand={True} vexpand={True}>
            <Paned.start>
                <Label text="Left panel" />
            </Paned.start>
            <Paned.end>
                <Label text="Right panel" />
            </Paned.end>
        </Paned>
    </Window>

ToolbarView ​

Named child groups use catalog spellings such as ToolbarView.topBar. Run aivi check --runnable path/to/main.aivi to validate them before launch; an unknown group reports the valid names from the widget catalog.

Adwaita toolbar container with top/bottom bars and content.

aivi
value view =
    <Window title="App">
        <ToolbarView>
            <ToolbarView.topBar>
                <HeaderBar />
            </ToolbarView.topBar>
            <Label text="Content" vexpand={True} />
        </ToolbarView>
    </Window>

Label ​

Text display widget.

aivi
value view =
    <Window title="App">
        <Label text="Hello, world!" wrap={True} halign="Start" xalign={0.0} />
    </Window>

Properties (extra): xalign, yalign, widthChars, singleLineMode

  • xalign (F64) — horizontal text alignment within the widget; 0.0 = left, 0.5 = center, 1.0 = right
  • yalign (F64) — vertical text alignment within the widget
  • widthChars (I64) — minimum width in characters; useful for stable layouts
  • singleLineMode (Bool) — when True, forces text to render as a single line (truncates or scrolls)

Button ​

Clickable button.

aivi
value view =
    <Window title="App">
        <Button label="Click me" halign="Center" />
    </Window>

Extra properties: iconName, useUnderline, receivesDefault

  • iconName (Text) — symbolic icon name; when set alongside label, produces an icon+label button; when set without label, produces an icon-only button (e.g. "list-add-symbolic")
  • useUnderline (Bool) — when True, a _ in label marks the next character as a mnemonic accelerator
  • receivesDefault (Bool) — when True, this button activates when Enter is pressed in its window (if no focused widget intercepts the key)

Gesture events (also available on Box, Label, Image):

  • onSecondaryClick (Unit) — fires on right-button / secondary-button click
  • onLongPress (Unit) — fires after a long press gesture is held
  • onSwipeLeft (Unit) — fires when a left-ward swipe is detected
  • onSwipeRight (Unit) — fires when a right-ward swipe is detected

Entry ​

Single-line text input.

aivi
value view =
    <Window title="App">
        <Entry placeholder="Type something..." hexpand={True} primaryIconName="system-search-symbolic" />
    </Window>

Extra properties: primaryIconName, secondaryIconName

  • primaryIconName (Text) — icon name for the leading (start) icon slot; use a symbolic icon name such as "system-search-symbolic"
  • secondaryIconName (Text) — icon name for the trailing (end) icon slot; commonly used for a clear button ("edit-clear-symbolic")

Events: onChange (Text), onActivated (Unit), onFocusIn (Unit), onFocusOut (Unit)

Switch ​

Toggle switch.

aivi
value view =
    <Window title="App">
        <Switch active={True} halign="Center" valign="Center" />
    </Window>

CheckButton ​

Checkbox with label.

aivi
value view =
    <Window title="App">
        <CheckButton label="Enable feature" active={False} />
    </Window>

ToggleButton ​

Button that stays pressed.

aivi
value view =
    <Window title="App">
        <ToggleButton label="Bold" active={False} />
    </Window>

SpinButton ​

Numeric spinner input.

aivi
value view =
    <Window title="App">
        <SpinButton value={5.0} min={0.0} max={10.0} step={1.0} digits={0} />
    </Window>

Scale ​

Slider for numeric values.

aivi
value view =
    <Window title="App">
        <Scale value={50.0} min={0.0} max={100.0} step={1.0} drawValue={True} valuePos="Bottom" hexpand={True} />
    </Window>

Extra properties: valuePos, fillLevel

  • valuePos (Text) — position of the numeric label when drawValue is True; one of "Top", "Bottom", "Left", "Right"
  • fillLevel (F64) — fills the track up to this value (also enables the fill-level indicator automatically); useful for buffered-progress UIs

Image ​

Image display.

aivi
value view =
    <Window title="App">
        <Image iconName="folder-symbolic" pixelSize={48} halign="Center" />
    </Window>

Spinner ​

Activity indicator.

aivi
value view =
    <Window title="App">
        <Spinner spinning={True} halign="Center" valign="Center" />
    </Window>

ProgressBar ​

Progress display.

aivi
value view =
    <Window title="App">
        <ProgressBar fraction={0.6} hexpand={True} />
    </Window>

Revealer ​

Animated visibility toggle.

aivi
value view =
    <Window title="App">
        <Revealer revealed={True} transitionType="slide-down">
            <Label text="Now you see me" />
        </Revealer>
    </Window>

Separator ​

Visual divider line.

aivi
value view =
    <Window title="App">
        <Box orientation="Vertical">
            <Label text="Above" />
            <Separator orientation="Horizontal" />
            <Label text="Below" />
        </Box>
    </Window>

StatusPage ​

Placeholder page with icon and description.

aivi
value view =
    <Window title="App">
        <StatusPage title="Nothing here yet" description="Add items to get started" iconName="folder-open-symbolic" />
    </Window>

Clamp ​

Width-constraining container.

aivi
value view =
    <Window title="App">
        <Clamp maximumSize={600} tighteningThreshold={400}>
            <Label text="Content constrained to 600 px" wrap={True} />
        </Clamp>
    </Window>

Informational banner strip.

aivi
value view =
    <Window title="App">
        <Box orientation="Vertical">
            <Banner title="You are offline" buttonLabel="Retry" revealed={True} />
            <Label text="Main content" vexpand={True} />
        </Box>
    </Window>

Frame ​

Container with an optional label border.

aivi
value view =
    <Window title="App">
        <Frame label="Details">
            <Label text="Inside the frame" marginTop={8} />
        </Frame>
    </Window>

Viewport ​

Low-level scrollable viewport.

aivi
value view =
    <Window title="App">
        <ScrolledWindow vexpand={True}>
            <Viewport>
                <Label text="Scrollable content" />
            </Viewport>
        </ScrolledWindow>
    </Window>

Adwaita preference rows ​

These widgets are designed for settings/preferences UIs. They extend gtk::ListBoxRow and should be placed inside a ListBox.

ActionRow ​

A row with title, optional subtitle, and suffix widgets.

aivi
value view =
    <Window title="App">
        <ListBox>
            <ActionRow title="Notifications" subtitle="Allow alerts">
                <ActionRow.suffix>
                    <Switch active={True} valign="Center" />
                </ActionRow.suffix>
            </ActionRow>
        </ListBox>
    </Window>

Properties: title, subtitle, activatable
Events: onActivated (Unit)
Children: prefix (sequence — widgets placed before the title), suffix (sequence — widgets placed after the title)

ExpanderRow ​

An expandable row that reveals child rows.

aivi
value view =
    <Window title="App">
        <ListBox>
            <ExpanderRow title="Advanced" subtitle="More options" expanded={False}>
                <ExpanderRow.rows>
                    <ActionRow title="Option A" />
                    <ActionRow title="Option B" />
                </ExpanderRow.rows>
            </ExpanderRow>
        </ListBox>
    </Window>

Properties: title, subtitle, expanded
Events: onExpanded (Bool) — fires each time the row is expanded or collapsed
Children: rows (sequence)

SwitchRow ​

A preference row with an embedded switch.

aivi
value view =
    <Window title="App">
        <ListBox>
            <SwitchRow title="Dark mode" subtitle="Use dark colour scheme" active={False} />
        </ListBox>
    </Window>

Properties: title, subtitle, active
Events: onToggled (Bool — new active state)

SpinRow ​

A preference row with an embedded spin button.

aivi
value view =
    <Window title="App">
        <ListBox>
            <SpinRow title="Font size" value={12.0} min={8.0} max={32.0} step={1.0} />
        </ListBox>
    </Window>

Properties: title, subtitle, value, min, max, step
Events: onValueChanged (Float)

EntryRow ​

A preference row with an embedded text entry.

aivi
value view =
    <Window title="App">
        <ListBox>
            <EntryRow title="Username" text="" />
        </ListBox>
    </Window>

Properties: title, text
Events: onChange (Text), onActivated (Unit), onFocusIn (Unit), onFocusOut (Unit)


List and selection ​

ListBox ​

A vertical list container for rows.

aivi
value view =
    <Window title="App">
        <ListBox selectionMode="None">
            <ListBoxRow>
                <Label text="Row one" />
            </ListBoxRow>
            <ListBoxRow>
                <Label text="Row two" />
            </ListBoxRow>
        </ListBox>
    </Window>

Properties: selectionMode (None|Single|Browse|Multiple), showSeparators (Bool)
Events: onRowActivated (Int — zero-based row index)
Children: children (sequence)

ListBoxRow ​

A single row in a ListBox.

aivi
value view =
    <Window title="App">
        <ListBox>
            <ListBoxRow activatable={True}>
                <Label text="Clickable row" marginStart={12} marginEnd={12} />
            </ListBoxRow>
        </ListBox>
    </Window>

Properties: activatable
Events: onActivated (Unit)
Children: child (single)

ListView ​

A factory-backed GTK list for large item sequences. It accepts ordinary child widgets, but mounts them through GTK list items so scrolling stays efficient. Wrap it in a ScrolledWindow when the content should scroll.

aivi
value view =
    <Window title="App">
        <ScrolledWindow vexpand={True}>
            <ListView showSeparators={True} singleClickActivate={True} onActivate={.}>
                <Label text="Thread A" />
                <Label text="Thread B" />
                <Label text="Thread C" />
            </ListView>
        </ScrolledWindow>
    </Window>

Properties: showSeparators, enableRubberband, singleClickActivate (Bool)
Events: onActivate (Int — zero-based item index)
Children: children (sequence — default)

GridView ​

A factory-backed GTK grid for large tile collections. Like ListView, it accepts ordinary child widgets and virtualizes scrolling/layout through GTK’s grid item machinery.

aivi
value view =
    <Window title="App">
        <ScrolledWindow vexpand={True}>
            <GridView minColumns={2} maxColumns={4} singleClickActivate={True} onActivate={.}>
                <Button label="Card 1" />
                <Button label="Card 2" />
                <Button label="Card 3" />
                <Button label="Card 4" />
            </GridView>
        </ScrolledWindow>
    </Window>

Properties: enableRubberband, singleClickActivate (Bool), minColumns, maxColumns (Int)
Events: onActivate (Int — zero-based item index)
Children: children (sequence — default)

A dropdown selector from a comma-separated list of strings.

aivi
value view =
    <Window title="App">
        <DropDown items="Red,Green,Blue" selected={0} halign="Start" />
    </Window>

Properties: items (comma-separated text), selected (Int)
Events: onSelectionChanged (Int — selected index)


Utility ​

SearchEntry ​

A text entry styled for search input with debounced onSearchChanged.

aivi
value view =
    <Window title="App">
        <SearchEntry placeholder="Search..." hexpand={True} />
    </Window>

Properties: text, placeholder
Events: onChange (Text), onActivated (Unit), onSearchChanged (Text — debounced)

Expander ​

A collapsible container with a label toggle.

aivi
value view =
    <Window title="App">
        <Expander label="Details" expanded={False}>
            <Label text="Hidden until expanded" />
        </Expander>
    </Window>

Properties: label, expanded
Events: onExpanded (Bool) — fires each time the expander is expanded or collapsed
Children: child (single)


Adwaita push-based navigation stack. Children must be NavigationPage widgets.

aivi
value view =
    <Window title="App">
        <NavigationView>
            <NavigationPage title="Home" tag="home">
                <Label text="Home page" halign="Center" valign="Center" vexpand={True} />
            </NavigationPage>
            <NavigationPage title="Details" tag="details">
                <Label text="Details page" halign="Center" valign="Center" vexpand={True} />
            </NavigationPage>
        </NavigationView>
    </Window>

Children: pages (sequence of NavigationPage)

A page within a NavigationView.

aivi
value view =
    <Window title="App">
        <NavigationView>
            <NavigationPage title="Profile" tag="profile">
                <ToolbarView>
                    <ToolbarView.topBar>
                        <HeaderBar />
                    </ToolbarView.topBar>
                    <Label text="Profile content" halign="Center" valign="Center" vexpand={True} />
                </ToolbarView>
            </NavigationPage>
        </NavigationView>
    </Window>

Properties: title, tag
Events: onShowing (Unit) — fired when the page is pushed onto the navigation stack; onHiding (Unit) — fired when the page is popped
Children: content (single)

ToastOverlay ​

An overlay that can display transient toast notifications (toasts are shown at runtime via the signal engine, not via markup children).

aivi
value view =
    <Window title="App">
        <ToastOverlay>
            <ToastOverlay.content>
                <Label text="Main content" halign="Center" valign="Center" vexpand={True} />
            </ToastOverlay.content>
        </ToastOverlay>
    </Window>

Children: content (single)


Preferences and forms ​

PreferencesWindow ​

An Adwaita preferences window with a searchable page switcher.

aivi
value view =
    <PreferencesWindow title="Settings" defaultWidth={600} defaultHeight={400} searchEnabled={True}>
        <PreferencesPage title="General" iconName="preferences-system-symbolic">
            <PreferencesGroup title="Appearance" description="Adjust how the app looks">
                <SwitchRow title="Dark mode" />
            </PreferencesGroup>
        </PreferencesPage>
    </PreferencesWindow>

Properties: title, defaultWidth (Int), defaultHeight (Int), searchEnabled (Bool)
Children: pages (sequence of PreferencesPage)

PreferencesPage ​

A named page inside a PreferencesWindow.

aivi
value view =
    <PreferencesWindow title="Settings">
        <PreferencesPage title="General" iconName="preferences-system-symbolic">
            <PreferencesGroup title="Behaviour">
                <SwitchRow title="Auto-save" active={True} />
            </PreferencesGroup>
        </PreferencesPage>
    </PreferencesWindow>

Properties: title, iconName
Children: children (sequence of PreferencesGroup)

PreferencesGroup ​

A titled group of preference rows within a PreferencesPage.

aivi
value view =
    <PreferencesWindow title="Settings">
        <PreferencesPage title="General" iconName="preferences-system-symbolic">
            <PreferencesGroup title="Privacy" description="Control data usage">
                <SwitchRow title="Analytics" active={False} />
                <SwitchRow title="Crash reports" active={True} />
            </PreferencesGroup>
        </PreferencesPage>
    </PreferencesWindow>

Properties: title, description
Children: children (sequence — any preference rows or widgets)

ComboRow ​

A preference row with a drop-down selector.

aivi
value view =
    <Window title="App">
        <ListBox>
            <ComboRow title="Theme" items="Light,Dark,System" selected={2} />
        </ListBox>
    </Window>

Properties: title, subtitle, items (comma-separated), selected (Int)
Events: onSelectionChanged (Int — zero-based index of selected item)

PasswordEntryRow ​

A preference row styled for password input with reveal toggle.

aivi
value view =
    <Window title="App">
        <ListBox>
            <PasswordEntryRow title="Password" text="" />
        </ListBox>
    </Window>

Properties: title, text
Events: onChange (Text), onActivated (Unit), onFocusIn (Unit), onFocusOut (Unit)


Layout overlays ​

Overlay ​

Stacks widgets on top of a main content widget. Use content for the base layer and overlay for widgets that float above it.

aivi
value view =
    <Window title="App">
        <Overlay>
            <Label text="Base content" halign="Center" valign="Center" hexpand={True} vexpand={True} />
            <Overlay.overlay>
                <Label text="Floating label" halign="End" valign="End" marginEnd={12} marginBottom={12} />
            </Overlay.overlay>
        </Overlay>
    </Window>

Children: content (single — base widget), overlay (sequence — overlaid widgets)

MultilineEntry ​

A multi-line text editor backed by gtk::TextView.

aivi
value view =
    <Window title="App">
        <MultilineEntry text="" editable={True} monospace={False} topMargin={8} bottomMargin={8} vexpand={True} />
    </Window>

Properties: text, editable (Bool), monospace (Bool), topMargin (Int), bottomMargin (Int), leftMargin (Int), rightMargin (Int)
Events: onChange (Text), onFocusIn (Unit), onFocusOut (Unit)

Picture ​

Displays an image from a file path or a GResource path, with configurable content-fit behaviour. Use Picture instead of Image when you need layout-aware scaling.

aivi
value view =
    <Window title="App">
        <Picture filename="/usr/share/pixmaps/logo.png" contentFit="contain" canShrink={True} hexpand={True} vexpand={True} />
    </Window>

Properties:

  • filename (Text) — absolute file path to load; empty string clears the image
  • resource (Text) — GResource path (e.g. /com/example/app/logo.png); empty clears
  • contentFit (Text) — one of contain (default), fill, cover, scale-down
  • altText (Text) — accessibility description
  • canShrink (Bool) — allow the picture to shrink below its natural size (default True)

WebView ​

Strict embedded HTML viewer backed by WebKitGTK. Load HTML through html. Safe defaults stay on: JavaScript disabled, session/storage ephemeral, permission requests denied, and navigation/new windows blocked. When links should open externally, use portal.openUri from app state instead of relying on in-widget browsing.

aivi
value view =
    <Window title="App">
        <WebView html={"<article><h1>Hello</h1><p>Rendered by WebKit.</p></article>"} hexpand={True} vexpand={True} />
    </Window>

Properties: html (Text)

ViewStack navigation ​

ViewStack is the primary Adwaita page-navigation container. Page selection is exposed as visibleChildName, so explicit controls can update the same signal without introducing mutable cross-widget references. The association-dependent ViewSwitcher, ViewSwitcherBar, and ViewSwitcherTitle widgets are intentionally not registered until AIVI has a typed widget-reference model; advertising an unbound switcher would create a control that cannot navigate.

aivi
signal activePage : Signal Text = "home"

value view =
    <Window title="App">
        <ToolbarView>
            <ToolbarView.topBar>
                <HeaderBar />
            </ToolbarView.topBar>
            <ViewStack visibleChildName={activePage}>
                <ViewStack.pages>
                    <ViewStackPage name="home" title="Home" iconName="go-home-symbolic">
                        <Label text="Home page" halign="Center" valign="Center" vexpand={True} />
                    </ViewStackPage>
                    <ViewStackPage name="search" title="Search" iconName="edit-find-symbolic">
                        <Label text="Search page" halign="Center" valign="Center" vexpand={True} />
                    </ViewStackPage>
                </ViewStack.pages>
            </ViewStack>
        </ToolbarView>
    </Window>

ViewStack properties:

  • visibleChildName (Text) — name of the currently visible page

ViewStack events:

  • onSwitch (Text) — fires with the name of the newly visible page when navigation changes

ViewStack children:

  • pages — sequence of ViewStackPage wrappers. Set each wrapper's name, title, and iconName; the bridge uses those values when adding the page. The stack's visibleChildName selects a page by that name; it does not rename child widgets.

AlertDialog ​

AlertDialog is a modal Adwaita dialog with configurable response buttons. Present and dismiss it by binding a Bool signal to the visible property.

aivi
signal showConfirm : Signal Bool = False
signal lastResponse : Signal Text = ""

value view =
    <Window title="App">
        <AlertDialog visible={showConfirm} heading="Delete item?" body="This action cannot be undone." defaultResponse="delete" closeResponse="cancel" responses="delete:Delete:destructive|cancel:Cancel" />
        <Button label="Delete" cssClasses="destructive-action" />
    </Window>

Properties:

  • visible (Bool) — True presents the dialog, False closes it
  • heading (Text) — dialog heading text
  • body (Text) — dialog body text
  • defaultResponse (Text) — ID of the response activated by pressing Enter
  • closeResponse (Text) — ID of the response used when the dialog is closed by the user
  • responses (Text) — pipe-separated list of id:Label or id:Label:appearance entries, where appearance is one of default, suggested, destructive. Example: "ok:OK:suggested|cancel:Cancel"

Events:

  • onResponse (Text) — fires with the response ID when the user activates a response

Calendar ​

Month calendar with optional day selection.

aivi
signal selectedDay : Signal Int = 1
signal selectedMonth : Signal Int = 0
signal selectedYear : Signal Int = 2025

value view =
    <Window title="App">
        <Calendar year={selectedYear} month={selectedMonth} day={selectedDay} onDaySelected={.} />
    </Window>

Properties: year, month, day

  • year (I64) — displayed year
  • month (I64) — displayed month, 0-based (0 = January, 11 = December)
  • day (I64) — selected day of the month (1–31)

Events:

  • onDaySelected (Unit) — fires when the user clicks a day

FlowBox + FlowBoxChild ​

Reflowing grid of child widgets. Children wrap to the next row when the available width is exhausted.

aivi
value view =
    <Window title="App">
        <ScrolledWindow hexpand={True} vexpand={True}>
            <FlowBox selectionMode="Single" rowSpacing={6} columnSpacing={6}>
                <FlowBoxChild>
                    <Label text="Item A" />
                </FlowBoxChild>
                <FlowBoxChild>
                    <Label text="Item B" />
                </FlowBoxChild>
                <FlowBoxChild>
                    <Label text="Item C" />
                </FlowBoxChild>
            </FlowBox>
        </ScrolledWindow>
    </Window>

FlowBox properties: selectionMode, rowSpacing, columnSpacing

  • selectionMode (Text) — "None", "Single", "Browse", or "Multiple"
  • rowSpacing (I64) — pixels of space between rows
  • columnSpacing (I64) — pixels of space between columns

FlowBox events:

  • onChildActivated (Unit) — fires when a child is activated (double-clicked or Enter)

FlowBox children: children — sequence of FlowBoxChild widgets

FlowBoxChild children: content — single child slot (the widget displayed inside the cell)

A button that opens a Popover when clicked.

aivi
signal menuOpen : Signal Bool = False

value view =
    <Window title="App">
        <Window.titlebar>
            <HeaderBar>
                <HeaderBar.end>
                    <MenuButton iconName="open-menu-symbolic" onToggled={open => menuOpen}>
                        <MenuButton.popover>
                            <Popover>
                                <Popover.content>
                                    <Box orientation="Vertical" spacing={4} marginTop={8} marginBottom={8} marginStart={8} marginEnd={8}>
                                        <Button label="Settings" />
                                        <Button label="About" />
                                    </Box>
                                </Popover.content>
                            </Popover>
                        </MenuButton.popover>
                    </MenuButton>
                </HeaderBar.end>
            </HeaderBar>
        </Window.titlebar>
        <Label text="Content" />
    </Window>

Properties: label, iconName, active, useUnderline

  • label (Text) — button label text (use iconName for icon-only buttons)
  • iconName (Text) — icon name from the icon theme (e.g. "open-menu-symbolic")
  • active (Bool) — whether the popover is currently open
  • useUnderline (Bool) — interpret _ in the label as a mnemonic underline

Events:

  • onToggled (Bool) — fires with True when the popover opens, False when it closes

Children: popover — single Popover child slot

Popover ​

A floating overlay widget anchored to its parent. Typically used as the child of MenuButton.

aivi
value view =
    <Window title="App">
        <MenuButton label="Options">
            <MenuButton.popover>
                <Popover autohide={True} hasArrow={True} onClosed={.}>
                    <Popover.content>
                        <Label text="Hello from popover!" marginStart={8} marginEnd={8} marginTop={8} marginBottom={8} />
                    </Popover.content>
                </Popover>
            </MenuButton.popover>
        </MenuButton>
    </Window>

Properties: autohide, hasArrow

  • autohide (Bool) — close the popover automatically when focus leaves it (default True)
  • hasArrow (Bool) — draw a pointing arrow towards the anchor widget (default True)

Events:

  • onClosed (Unit) — fires when the popover is dismissed

Children: content — single child slot for the popover body widget


CenterBox ​

A three-slot horizontal container that aligns a center child between optional start and end children.

aivi
value view =
    <Window title="App">
        <CenterBox hexpand={True}>
            <CenterBox.start>
                <Button label="Back" />
            </CenterBox.start>
            <CenterBox.center>
                <Label text="Title" />
            </CenterBox.center>
            <CenterBox.end>
                <Button label="Forward" />
            </CenterBox.end>
        </CenterBox>
    </Window>

Children: start (single), center (single — default), end (single)


AboutDialog ​

Adwaita About dialog showing application metadata. Acts as a top-level window; set visible reactively to show or hide it.

aivi
signal showAbout : Signal Bool = False

value view =
    <Window title="App">
        <AboutDialog visible={showAbout} appName="My App" version="1.0.0" developerName="Jane Doe" website="https://example.com" issueUrl="https://github.com/example/issues" licenseType="MIT" applicationIcon="my-app" />
        <Button label="About" onClick={True} />
    </Window>

Properties: visible, appName, version, developerName, comments, website, issueUrl, licenseType, applicationIcon

  • licenseType (Text) — one of the GLib/GTK license identifiers: "MIT", "GPL-2.0", "GPL-3.0", "LGPL-2.1", "LGPL-3.0", "AGPL-3.0", "Apache-2.0", "MPL-2.0", "Custom", "Unknown"

SplitButton ​

A combined button + dropdown arrow that opens a Popover for secondary actions.

aivi
value view =
    <Window title="App">
        <SplitButton label="Save" onClick={.} hexpand={False}>
            <SplitButton.popover>
                <Popover>
                    <Popover.content>
                        <Box orientation="Vertical" spacing={4}>
                            <Button label="Save As…" />
                            <Button label="Export…" />
                        </Box>
                    </Popover.content>
                </Popover>
            </SplitButton.popover>
        </SplitButton>
    </Window>

Properties: label, iconName

  • label (Text) — text for the main button half
  • iconName (Text) — icon name alternative to label

Events: onClick (Unit) — fires when the main button half is clicked

Children: popover (single — a Popover widget for the dropdown)


An adaptive two-panel layout (sidebar + content) that collapses to a single column on narrow displays. Both panels should contain NavigationPage widgets.

aivi
value view =
    <Window title="App" defaultWidth={900} defaultHeight={600}>
        <NavigationSplitView showContent={True} sidebarWidthFraction={0.3}>
            <NavigationSplitView.sidebar>
                <NavigationPage title="Sidebar">
                    <Label text="Sidebar content" />
                </NavigationPage>
            </NavigationSplitView.sidebar>
            <NavigationSplitView.content>
                <NavigationPage title="Content">
                    <Label text="Main content" />
                </NavigationPage>
            </NavigationSplitView.content>
        </NavigationSplitView>
    </Window>

Properties: showContent, sidebarWidthFraction, minSidebarWidth, maxSidebarWidth, sidebarPosition

  • showContent (Bool) — when collapsed, whether the content panel is shown (vs. the sidebar)
  • sidebarWidthFraction (Float) — sidebar width as a fraction of the total width (default 0.25)
  • minSidebarWidth / maxSidebarWidth (Float) — clamp sidebar width in pixels
  • sidebarPosition (Text) — "Start" (default) or "End"

Events: onShowContent (Bool) — fires when showContent changes

Children: sidebar (single), content (single — default)


OverlaySplitView ​

Like NavigationSplitView but the sidebar slides over the content rather than pushing it.

aivi
signal sidebarOpen : Signal Bool = False

value view =
    <Window title="App" defaultWidth={800} defaultHeight={600}>
        <OverlaySplitView showSidebar={sidebarOpen}>
            <OverlaySplitView.sidebar>
                <Box orientation="Vertical" spacing={8} marginStart={12} marginTop={12}>
                    <Label text="Navigation" />
                </Box>
            </OverlaySplitView.sidebar>
            <OverlaySplitView.content>
                <Label text="Content" halign="Center" valign="Center" />
            </OverlaySplitView.content>
        </OverlaySplitView>
    </Window>

Properties: showSidebar, sidebarPosition, sidebarWidthFraction, minSidebarWidth, maxSidebarWidth

  • showSidebar (Bool) — show or hide the overlay sidebar
  • sidebarPosition (Text) — "Start" (default) or "End"

Events: onShowSidebar (Bool) — fires when showSidebar changes

Children: sidebar (single), content (single — default)


TabView + TabPage + TabBar ​

A tabbed interface. TabView holds pages; TabBar provides the tab strip.

aivi
signal activeTab : Signal Int = 0

value view =
    <Window title="App">
        <Box orientation="Vertical">
            <TabView selectedPage={activeTab} onSelectedPageChanged={.} hexpand={True} vexpand={True}>
                <TabView.tabBar>
                    <TabBar autohide={False} expandTabs={True} />
                </TabView.tabBar>
                <TabView.pages>
                    <TabPage title="Documents">
                        <TabPage.content>
                            <Label text="Documents tab" halign="Center" valign="Center" />
                        </TabPage.content>
                    </TabPage>
                    <TabPage title="Settings" needsAttention={True}>
                        <TabPage.content>
                            <Label text="Settings tab" halign="Center" valign="Center" />
                        </TabPage.content>
                    </TabPage>
                </TabView.pages>
            </TabView>
        </Box>
    </Window>

TabView ​

Properties: selectedPage (Int — zero-based index)
Events: onPageAdded (Unit), onPageClosed (Unit), onSelectedPageChanged (Unit)
Children: pages (sequence of TabPage — default), tabBar (single TabBar)

TabPage ​

Properties: visible, title, needsAttention (Bool — shows a dot indicator), loading (Bool — shows a spinner)
Children: content (single — default)

TabBar ​

Properties: autohide (Bool — hides bar when there is only one page), expandTabs (Bool — tabs expand to fill the bar width)


A swipe carousel backed by adw::Carousel. Attach CarouselIndicatorDots or CarouselIndicatorLines as the dots/lines child to get navigation indicators.

aivi
value view =
    <Window title="App">
        <Box orientation="Vertical" spacing={8} hexpand={True} vexpand={True}>
            <Carousel spacing={16} interactive={True} hexpand={True} vexpand={True} onPageChanged={.} onSwipeLeft={.} onSwipeRight={.}>
                <Carousel.dots>
                    <CarouselIndicatorDots />
                </Carousel.dots>
                <Carousel.pages>
                    <Label text="Page 1" halign="Center" valign="Center" />
                    <Label text="Page 2" halign="Center" valign="Center" />
                    <Label text="Page 3" halign="Center" valign="Center" />
                </Carousel.pages>
            </Carousel>
        </Box>
    </Window>

Carousel properties: spacing (Int), revealDuration (Int — ms), interactive (Bool)
Carousel events: onPageChanged (Int — zero-based page index), onSwipeLeft (Unit), onSwipeRight (Unit)
Carousel children: pages (sequence — default), dots (single CarouselIndicatorDots), lines (single CarouselIndicatorLines)

CarouselIndicatorDots and CarouselIndicatorLines have no widget-specific properties; they automatically link to their parent Carousel.


Grid + GridChild ​

A two-dimensional grid layout. Each child must be wrapped in a GridChild that specifies its position.

aivi
value view =
    <Window title="App">
        <Grid rowSpacing={8} columnSpacing={8} marginStart={12} marginEnd={12} marginTop={12} marginBottom={12}>
            <GridChild column={0} row={0} columnSpan={2}>
                <GridChild.content>
                    <Label text="Wide header" hexpand={True} />
                </GridChild.content>
            </GridChild>
            <GridChild column={0} row={1}>
                <GridChild.content>
                    <Button label="A" />
                </GridChild.content>
            </GridChild>
            <GridChild column={1} row={1}>
                <GridChild.content>
                    <Button label="B" />
                </GridChild.content>
            </GridChild>
        </Grid>
    </Window>

Grid ​

Properties: rowSpacing, columnSpacing (Int), rowHomogeneous, columnHomogeneous (Bool)
Children: children (sequence of GridChild — default)

GridChild ​

Properties: column, row, columnSpan, rowSpan (Int — default span is 1)
Children: content (single — default)


FileDialog ​

A native file-chooser dialog backed by gtk::FileChooserNative. Set visible to True to show the dialog; the response is delivered via onResponse.

aivi
signal dialogOpen : Signal Bool = False

value view =
    <Window title="App">
        <FileDialog visible={dialogOpen} title="Open file" mode="Open" acceptLabel="Open" cancelLabel="Cancel" onResponse={.}>
            <Button label="Open file…" onClick={True} />
        </FileDialog>
    </Window>

Properties:

PropertyTypeDescription
visibleBoolShow (True) or hide (False) the dialog
titleTextWindow title of the chooser
modeText"Open" (default) or "Save"
acceptLabelTextLabel for the accept button
cancelLabelTextLabel for the cancel button

Events: onResponse (Int) — AIVI's response mapping: 1 = accepted, 0 = cancelled, -4 = window deleted, custom responses retain their integer value, and other responses map to -1. These are not the raw numeric values of gtk::ResponseType.

Additional schema entries ​

The current schema also registers the following names. They have no worked walkthrough on this page yet; consult crates/aivi-gtk/src/schema.rs for the exact accepted properties, events, and child slots, and crates/aivi-gtk/src/host.rs for their runtime wiring.

AreaRegistered names
GTK controls and viewsInfoBar, LevelBar, LinkButton, Stack, StackSwitcher, StackSidebar, TreeExpander, GLArea
Adwaita controls and layoutBreakpoint, Avatar, Squeezer, Flap, ButtonContent, WindowTitle, MultiLayoutView, AdwDialog
Gestures and controllersGestureClick, GestureDrag, GestureSwipe, GestureLongPress, GestureRotate, GestureZoom, DragSource, DropTarget, ShortcutController
StylingCssProvider

Do not infer an arbitrary GTK API from a widget's name. Association-dependent widgets are exposed only when the bridge can represent and execute their required relationship.

(c) 2026 by Andreas Herd