SurfaceNode is one piece of the tree:
kind: container orleaflayout: LayoutSpeccontent: what to draw (leaf only)children: child nodes (containers)id: SurfaceIdhit/hit_data: pointer routingsemantics: optional accessibility metadatafocus_scope: keep keyboard focus inside this subtree
hit (or use a constructor that sets it) on anything you want to click.
Constructors vs manual nodes
Many controls have helpers onSurfaceNode:
section, tabs, form_row, color_swatch, and gradient_swatch, build the struct manually:
Structural leaves
panel (PanelSpec)
Rounded card background with optional border and shadow.
| Field | Purpose |
|---|---|
background | Fill color (required) |
border, shadow, highlight_edge | Chrome |
radius, border_width | Corner and stroke |
rect (RectStyle)
Flat filled or bordered rectangle. Use for dividers, highlights, custom backgrounds.
| Field | Purpose |
|---|---|
fill | Background color |
border, border_width, radius, corners | Optional outline |
spacer (container kind)
Empty node. Size comes from LayoutSpec (often .fill to push siblings).
Text and actions
label (LabelSpec)
| Field | Default | Notes |
|---|---|---|
text | required | UTF-8 |
font_size | 14 | |
color | theme foreground | null = theme default |
baseline_offset | auto | Fine-tune vertical alignment |
button (ButtonSpec)
| Field | Default | Notes |
|---|---|---|
text | required | |
font_size | 14 | |
hovered, pressed, disabled | false | Drive from input.hovered / input.active |
background, hover_background, pressed_background | theme | Optional overrides |
text_color, border, radius, padding | theme defaults |
hit = .button.
icon_button (IconButtonSpec)
| Field | Purpose |
|---|---|
icon | ?*const anyopaque image pointer |
fallback_text | Shown when icon is null |
icon_size, font_size | Layout |
selected, disabled | State |
background, selected_background, icon_color, border, radius | Colors |
hit = .icon_button.
Text input
text_input (TextInputSpec)
| Field | Purpose |
|---|---|
text | Committed UTF-8 from your InputBuffer |
preedit | IME composition string |
cursor_byte, selection_start_byte, selection_end_byte | Caret and selection |
placeholder | Shown when text is empty |
focused | Focus ring and cursor |
disabled, wrap | State |
background, text_color, placeholder_color, border, cursor, selection | Colors |
padding, radius | Chrome |
hit = .text_input. Pair with ui.InputBuffer(N) in app state and Wayland text-input protocol for IME.
Boolean and numeric controls
checkbox (CheckboxSpec)
| Field | Purpose |
|---|---|
label | Optional text beside box |
checked, disabled | State |
font_size, box_size, color | Layout and colors |
hit = .checkbox.
toggle (ToggleSpec)
| Field | Default |
|---|---|
checked, disabled | false |
width | 38 |
height | 22 |
color | theme accent |
hit = .toggle.
slider (SliderSpec)
| Field | Purpose |
|---|---|
value_q16 | 0..65535 (0%..100% in 16.16 fixed point) |
disabled | Gray out |
height, track_height, color | Layout |
hit = .slider. Default layout width is .fill.
number_input (NumberInputSpec)
Stepper with decrement/value/increment zones.
| Field | Purpose |
|---|---|
value_text | Display string |
font_size, height, min_width | Layout |
disabled | State |
background, button_background, text_color, border, radius | Colors |
hit = .number_value on the center field. Decrement/increment buttons use separate hit kinds (.number_decrement, .number_increment) when emitted.
progress (ProgressSpec)
Read-only bar.
| Field | Purpose |
|---|---|
value_q16 | Fill amount |
height, color | Layout |
Selection and color
select (SelectSpec)
Dropdown trigger or inline popup.
| Field | Purpose |
|---|---|
selected_text, placeholder | Display |
options | Slice of option labels |
selected_index, hover_index, scroll_offset | List state |
open | Popup visible |
mode | .trigger, .inline_popup, or .menu |
item_height, max_visible, font_size | Layout |
disabled | State |
hit = .select. Option rows use .select_option in overlay pass.
color_picker (ColorPickerSpec)
Inline SV square + hue/alpha bars.
| Field | Purpose |
|---|---|
color | Current Color |
alpha | 0..255 |
sv_size, bar_width, padding | Layout |
disabled, background, border, radius | State and chrome |
hit = .color_picker_sv on the saturation/value area. Hue and alpha bars have .color_picker_hue and .color_picker_alpha.
color_picker_popup (ColorPickerPopupSpec)
Larger popup variant used by settings. Pass hsv from ui.drawing.HSV.
color_swatch / gradient_swatch
Small preview tiles. Set layout to fixed size. gradient_swatch takes start, mid, end colors.
Navigation chrome
tabs (TabsSpec)
| Field | Purpose |
|---|---|
items | Slice of { .id, .label, .disabled } |
active | Selected index |
font_size, height, horizontal_padding, gap | Layout |
| Color fields | Active/inactive tab styling |
.tab. Build manually:
section (SectionSpec)
Section header with optional underline.
| Field | Purpose |
|---|---|
title | Header text |
font_size, color, underline, show_underline | Style |
form_row (FormRowSpec)
Settings-style label + value row.
| Field | Purpose |
|---|---|
label, value | Text |
label_width, label_font_size, truncate_label | Layout |
label_color, value_color | Colors |
list_row (ListRowSpec)
Selectable list item with optional icon and subtitle.
| Field | Purpose |
|---|---|
title, subtitle | Text |
icon, icon_size | Leading image |
selected | Highlight state |
Color and padding, radius, font_size | Chrome |
listRow(id, spec, hit_data). hit = .button, hit_data carries list index.
scrollbar (ScrollbarSpec)
| Field | Purpose |
|---|---|
state | ui.ScrollState (offset, content height, viewport) |
width, disabled | Layout |
track_color, thumb_color, radius | Colors |
hit = .scroll. Pair with app scroll offset updates on .scroll dispatch events.
Media
image (ImageSpec)
| Field | Purpose |
|---|---|
image | ?*const otter_render.Image |
fit | .contain, .cover, .cover_scaled, .stretch, .center |
source_rect, alpha, pixelated, flip_x, radius, corners | Rendering |
icon (IconSpec)
| Field | Purpose |
|---|---|
image | Optional bitmap |
fallback_text | Letter or symbol if no image |
fallback_font, font_size, color | Text fallback styling |
fill, circle_fill | Background behind glyph |
Hit kinds reference
HitKind | Control |
|---|---|
.button | button, list_row |
.text_input | text_input |
.checkbox | checkbox |
.toggle | toggle |
.slider | slider |
.icon_button | icon_button |
.number_decrement / .number_value / .number_increment | number_input |
.select / .select_option | select |
.color_picker_sv / .hue / .alpha | color_picker |
.tab | tabs |
.scroll | scrollbar |
.overlay | Queued overlays |
.generic | Custom; set manually |
hit_data: u64 to pass a list index, enum tag, or pointer cookie to your handler.
Disabled content
ButtonSpec.disabled, ToggleSpec.disabled, SelectSpec.disabled, and similar flags mark the control visually disabled and set HitFlags.enabled = false so hitTest skips them.
Next
- Input and overlays: wire hits to app logic
- Drawing primitives: lower-level helpers behind these emitters

