Layout System
Yazi's plugin UI system lets plugins render custom interface elements using a flexbox-like layout model with constraints and composable widgets.
Geometry Types
Rect
A rectangle with position and size.
| Field | Type | Description |
|---|---|---|
x | integer | Column offset |
y | integer | Row offset |
w | integer | Width in columns |
h | integer | Height in rows |
Pos
A position (x, y) coordinate.
local pos = ui.Pos { x = 5, y = 10 }
Constraint
Constraints define how space is distributed in a Layout.
| Constructor | Description |
|---|---|
Constraint.Ratio(a, b) | Proportional space (a out of b total) |
Constraint.Length(n) | Fixed length of n columns/rows |
Constraint.Min(n) | At least n columns/rows |
Constraint.Max(n) | At most n columns/rows |
ui.Layout()
:direction(ui.Layout.HORIZONTAL)
:constraints({
ui.Constraint.Ratio(1, 3), -- 1/3 of space
ui.Constraint.Ratio(2, 3), -- 2/3 of space
})
Layout
Arranges child elements according to constraints.
| Method | Description |
|---|---|
:direction(dir) | Layout.HORIZONTAL or Layout.VERTICAL |
:constraints([Constraint]) | Set distribution constraints |
:split(Rect) -> [Rect] | Divide a rect into sub-rects |
UI Elements
All elements are constructed with a table and rendered via the ui module.
Line
A single row of styled text (inline).
ui.Line { ui.Span("Hello"), ui.Span("World"):bold() }
Text
A multi-line block of text.
ui.Text {
ui.Line { "Line 1" },
ui.Line { "Line 2" },
}
List
A scrollable list of items.
| Field | Type | Default | Description |
|---|---|---|---|
items | [Line] | — | List items |
highlight | Style | — | Style for the selected item |
ui.List {
items = {
ui.Line { "Item A" },
ui.Line { "Item B" },
},
highlight = ui.Style():fg("blue"):bold(),
}
Bar
A horizontal or vertical bar (e.g., scrollbar, progress indicator).
ui.Bar(rect, ui.Bar.VERTICAL)
:symbol(ui.Bar.ASCII)
:style(ui.Style():fg("cyan"))
Border
Wraps content with a border frame.
ui.Border(rect, ui.Border.PLAIN)
| Style | Description |
|---|---|
Border.PLAIN | Straight lines (-, |, +) |
Border.ROUNDED | Rounded corners |
Border.DOUBLE | Double lines |
Border.THICK | Thick lines |
Border.EMPTY | No border (invisible) |
Gauge
A progress bar.
| Field | Type | Description |
|---|---|---|
percent | integer | Fill percentage (0–100) |
label | string | Center label text |
style | Style | Fill style |
ui.Gauge {
percent = 65,
label = "65%",
style = ui.Style():fg("green"),
}
Clear
Clears the entire area (erases all content).
ui.Clear(rect)
Table
A table with columns and rows.
ui.Table {
header = { "Name", "Size", "Modified" },
rows = {
{ "foo.txt", "1.2 KB", "2025-01-15" },
{ "bar.md", "4.5 KB", "2025-01-16" },
},
widths = { 20, 10, 15 },
}
Paragraph
A text paragraph with word wrapping.
ui.Paragraph {
text = ui.Line { "Long text that will wrap at the rect boundary..." },
wrap = ui.Paragraph.WORD_WRAP,
}
Sparkline
A mini sparkline chart.
ui.Sparkline {
data = { 1, 4, 2, 8, 5, 7, 3 },
max = 8,
style = ui.Style():fg("yellow"),
}
Rendering Example
local function my_widget(area)
local chunks = ui.Layout()
:direction(ui.Layout.VERTICAL)
:constraints({
ui.Constraint.Length(1),
ui.Constraint.Ratio(1, 1),
ui.Constraint.Length(1),
})
:split(area)
return {
ui.Border(chunks[1], ui.Border.PLAIN),
ui.Text { ui.Line { "Content area" } },
ui.Gauge { percent = 50, label = "progress" },
}
end
All UI elements accept a table constructor and can be styled with method chaining: ui.Span("text"):fg("red"):bold():italic().