HStackWidget
Arrange child widgets horizontally from left to right.
HStackWidget is a layout container that positions its children in a horizontal row. It automatically manages width distribution, allowing children to size based on content, fill available space, or use fixed widths.
Basic Usage
Create a horizontal layout using the fluent API with collection expression syntax:
dotnet runFocus Management
HStackWidget manages focus for all its descendant widgets. Use Tab to move focus forward and Shift+Tab to move backward through focusable children.
Simple Horizontal Layout
Arrange widgets side by side:
All children are positioned from left to right with their natural content widths.
Sizing Children
HStackWidget supports three sizing modes for children:
Content Sizing (Default)
Children size to their natural content width:
ctx.HStack(h => [
h.Text("Short"),
h.Text("Longer Text"),
h.Text("X")
])
// Each Text widget takes exactly the width it needs2
3
4
5
6
Fill Sizing
Children with .Fill() expand to consume remaining space:
When multiple children use .Fill(), space is distributed evenly:
ctx.HStack(h => [
h.Text("Left").Fill(),
h.Text("Right").Fill()
])
// Both children get 50% of available width2
3
4
5
Fixed Sizing
Children with .FixedWidth() take exactly the specified width:
ctx.HStack(h => [
h.Text("Label").FixedWidth(20),
h.TextBox(value, onChange).Fill()
])
// Label is always 20 cells wide2
3
4
5
Weighted Fill
Use weighted fills to distribute space proportionally:
ctx.HStack(h => [
h.Panel(sidebar).FillWidth(1), // Gets 1/3 of space
h.Panel(main).FillWidth(2) // Gets 2/3 of space
])2
3
4
Layout Algorithm
HStackWidget distributes width in two passes:
- Fixed Pass: Measure content-sized and fixed-width children, sum their widths
- Fill Pass: Distribute remaining width among fill children based on their weights
All children receive the full height of the HStack.
Focus Navigation
HStackWidget provides default keyboard bindings:
| Key | Action |
|---|---|
| Tab | Move focus to next focusable widget |
| Shift+Tab | Move focus to previous focusable widget |
Focus order follows the left-to-right order of children in the array.
Clipping
Content that extends beyond the HStack's bounds is clipped by default. Children cannot render outside the stack's area.
To allow overflow (not recommended), you would need to configure clipping at a lower level via the layout system.
Common Patterns
Form Layouts
Create label-value pairs:
ctx.VStack(v => [
v.HStack(h => [
h.Text("Name:").FixedWidth(15),
h.TextBox(state.Name)
.OnTextChanged(args => state.Name = args.NewText)
.Fill()
]),
v.HStack(h => [
h.Text("Email:").FixedWidth(15),
h.TextBox(state.Email)
.OnTextChanged(args => state.Email = args.NewText)
.Fill()
])
])2
3
4
5
6
7
8
9
10
11
12
13
14
Button Groups
Arrange multiple buttons horizontally:
ctx.HStack(h => [
h.Button("Save").OnClick(_ => Save()),
h.Text(" "),
h.Button("Cancel").OnClick(_ => Cancel()),
h.Text(" "),
h.Button("Help").OnClick(_ => ShowHelp())
])2
3
4
5
6
7
Toolbar Layouts
Create toolbars with left and right sections:
ctx.HStack(h => [
h.Text("File Edit View"),
h.Text("").Fill(), // Spacer pushes next items to right
h.Text("User: Admin")
])2
3
4
5
Two-Column Layouts
Split content into side-by-side columns:
ctx.HStack(h => [
h.Border(b => [
b.Text("Sidebar content")
]).FixedWidth(30),
h.Border(b => [
b.Text("Main content")
]).Fill()
])2
3
4
5
6
7
8
Combining with VStack
Build complex grid-like layouts:
ctx.VStack(v => [
v.HStack(h => [
h.Text("A"),
h.Text("B"),
h.Text("C")
]),
v.HStack(h => [
h.Text("D"),
h.Text("E"),
h.Text("F")
])
])2
3
4
5
6
7
8
9
10
11
12
Performance Considerations
- HStack measures all children during layout
- Content-sized children are measured with unbounded width constraints
- Fill children are measured after fixed space is allocated
- Large numbers of children may impact layout performance
Related Widgets
- VStackWidget - For vertical layouts
- BorderWidget - For adding borders to stack children
- ThemePanelWidget - For scoped theming of child widgets