4.3k

Drawer

A side-anchored surface with the same contract as dialog: rendered in place, title via the text attribute, visibility model-owned behind an if, and on-dismiss dispatched on Escape or click-outside so update clears the open flag. As with the dialog, the title chrome is engine-drawn and children stack over the full content box, so lead the body column with a fixed-height spacer. For the bottom-edge variant, see sheet.

drawer
A drawer surface rendered by the engine (light theme)
a side drawer with a title and stacked controls

Markup

<column padding="24">
  <button variant="outline" icon="menu" on-press="open_filters">Filters</button>
  <if test="{filters_open}">
    <drawer text="Filters" width="260" padding="24" on-dismiss="close_filters">
      <column gap="12">
        <spacer height="34"></spacer>
        <checkbox checked="{only_unread}" on-toggle="toggle_unread">Only unread</checkbox>
        <checkbox checked="{has_attachments}" on-toggle="toggle_attachments">Has attachments</checkbox>
        <switch checked="{compact_rows}" on-toggle="toggle_compact">Compact rows</switch>
      </column>
    </drawer>
  </if>
</column>

Zig builder

// Rendered only while model.filters_open is true; on_dismiss clears it in update.
ui.el(.drawer, .{ .text = "Filters", .width = 260, .padding = 24, .on_dismiss = .close_filters }, .{
    ui.column(.{ .gap = 12 }, .{
        ui.column(.{ .height = 34 }, .{}), // clears the engine-drawn title line
        ui.checkbox(.{ .text = "Only unread", .checked = model.only_unread, .on_toggle = .toggle_unread }),
        ui.checkbox(.{ .text = "Has attachments", .checked = model.has_attachments, .on_toggle = .toggle_attachments }),
        ui.el(.switch_control, .{ .text = "Compact rows", .checked = model.compact_rows, .on_toggle = .toggle_compact }, .{}),
    }),
})

Attributes

The drawer rejects gap — it layers children like the other stacking surfaces; put a column (or row) inside for flow.

AttributeDescription
textText value for text-bearing elements; a literal or one {binding}.
widthDefinite width (plain number): the element is exactly this wide; content neither shrinks nor overflows it. On resizable it is the initial width.
heightDefinite height (plain number): the element is exactly this tall; content neither shrinks nor overflows it.
paddingUniform padding (plain number).
on-dismissDismissible surfaces only (dialog, drawer, sheet, dropdown-menu): Msg dispatched when Escape or a click outside dismisses the surface, so the MODEL owns the close (clear the open flag in update). The engine hides the surface immediately as an optimistic echo; the source tree wins on the next rebuild.