Scroll
A container widget that provides scrolling capability for content that exceeds the available space.
The scroll widget displays a scrollbar indicator and handles keyboard navigation to move through content that doesn't fit in the visible viewport. It supports both vertical and horizontal scrolling orientations.
Basic Usage
Create a vertical scroll widget using the fluent API. The scroll widget automatically shows a scrollbar when content exceeds the viewport:
dotnet runKeyboard Navigation
Use ↑↓ arrow keys to scroll vertically, or ←→ for horizontal scrolling. PgUp/PgDn jumps by pages, and Home/End jumps to the start or end of content.
Horizontal Scrolling
For wide content like tables or long text lines, use HScroll():
dotnet runThe scrollbar appears at the bottom when content width exceeds the viewport width.
Scroll Events
Use the OnScroll() event handler to react to scroll position changes. The ScrollChangedEventArgs provides comprehensive information about the current scroll state:
dotnet runScrollChangedEventArgs Properties
| Property | Type | Description |
|---|---|---|
Offset | int | Current scroll offset after the change |
PreviousOffset | int | Scroll offset before the change |
ContentSize | int | Total size of content in characters |
ViewportSize | int | Size of visible viewport in characters |
MaxOffset | int | Maximum scroll offset (computed) |
IsScrollable | bool | Whether content exceeds viewport |
Progress | double | Scroll position as 0.0-1.0 value |
IsAtStart | bool | True when scrolled to the beginning |
IsAtEnd | bool | True when scrolled to the end |
Tracking Scroll Position
Display the current scroll position in your UI:
dotnet runInfinite Scroll
Load more content when the user scrolls near the end:
dotnet runScrollbar Visibility
Control whether the scrollbar is displayed:
Set showScrollbar: false to hide the scrollbar. The content remains scrollable via keyboard, but no visual indicator appears.
// With scrollbar (default)
ctx.VScroll(v => [...])
// Without scrollbar
ctx.VScroll(v => [...], showScrollbar: false)2
3
4
5
Keyboard Shortcuts
When the scroll widget is focused, these keys control scrolling:
| Key | Action |
|---|---|
↑ | Scroll up one line (vertical) |
↓ | Scroll down one line (vertical) |
← | Scroll left one column (horizontal) |
→ | Scroll right one column (horizontal) |
PgUp | Scroll up one page |
PgDn | Scroll down one page |
Home | Jump to start |
End | Jump to end |
Focus Management
Scroll widgets are focusable and can contain other focusable widgets:
- Tab moves focus from the scroll widget to the first focusable child
- Shift+Tab moves focus from children back to the scroll widget
- Arrow keys scroll when the scroll widget itself is focused
- Arrow keys navigate within children when a child is focused
ctx.VScroll(
v => [
v.Text("Use Tab to focus the button below"),
v.Button("Click Me").OnClick(_ => { /* ... */ }),
v.Text("More content..."),
v.Button("Another Button").OnClick(_ => { /* ... */ })
]
)2
3
4
5
6
7
8
The scroll widget automatically scrolls to keep focused children visible within the viewport.
Layout Behavior
By default, scroll widgets fill available space. Use layout extensions to control size:
// Fill available space (default)
ctx.VScroll(v => [...])
// Fixed height
ctx.VScroll(v => [...]).FixedHeight(10)
// Fixed width (for horizontal scroll)
ctx.HScroll(h => [...]).FixedWidth(50)
// Combined with other constraints
ctx.VScroll(v => [...])
.FixedHeight(15)
.Fill() // Fill width2
3
4
5
6
7
8
9
10
11
12
13
Content Size
The scroll widget measures its child content without constraints to determine the full content size. For vertical scrolling, this means content can be arbitrarily tall; for horizontal, arbitrarily wide. Be mindful when scrolling very large datasets (e.g., thousands of items) as all content must be measured and rendered, which may impact performance. For large lists, consider virtualization patterns or pagination.
Theming
Customize scrollbar appearance using theme elements:
var theme = Hex1bTheme.Create()
.Set(ScrollTheme.VerticalThumbCharacter, "█")
.Set(ScrollTheme.VerticalTrackCharacter, "░")
.Set(ScrollTheme.ThumbColor, Hex1bColor.Cyan)
.Set(ScrollTheme.FocusedThumbColor, Hex1bColor.Yellow)
.Set(ScrollTheme.TrackColor, Hex1bColor.DarkGray);
await using var terminal = Hex1bTerminal.CreateBuilder()
.WithHex1bApp((app, options) =>
{
options.Theme = theme;
return ctx => /* ... */;
})
.Build();
await terminal.RunAsync();2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Available Theme Elements
| Element | Type | Default | Description |
|---|---|---|---|
VerticalThumbCharacter | string | █ | Character for vertical scrollbar thumb |
VerticalTrackCharacter | string | ░ | Character for vertical scrollbar track |
HorizontalThumbCharacter | string | █ | Character for horizontal scrollbar thumb |
HorizontalTrackCharacter | string | ░ | Character for horizontal scrollbar track |
ThumbColor | Hex1bColor | Gray | Color of scrollbar thumb |
FocusedThumbColor | Hex1bColor | White | Color of thumb when scroll widget is focused |
TrackColor | Hex1bColor | DarkGray | Color of scrollbar track |
UpArrowCharacter | string | ▲ | Up arrow for vertical scrollbar |
DownArrowCharacter | string | ▼ | Down arrow for vertical scrollbar |
LeftArrowCharacter | string | ◀ | Left arrow for horizontal scrollbar |
RightArrowCharacter | string | ▶ | Right arrow for horizontal scrollbar |
Common Patterns
Scrollable List of Items
ctx.VScroll(
v => items.Select(item => v.Text(item)).ToArray()
)2
3
Scrollable Text Content
var lines = File.ReadAllLines("document.txt");
ctx.VScroll(
v => lines.Select(line => v.Text(line)).ToArray()
)2
3
4
Nested Scrolling
ctx.VStack(v => [
v.Text("Outer container"),
v.VScroll(
inner => [
inner.Text("Scrollable section 1"),
inner.Text("Content...")
]
).FixedHeight(5),
v.Text("Between sections"),
v.VScroll(
inner => [
inner.Text("Scrollable section 2"),
inner.Text("More content...")
]
).FixedHeight(5)
])2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Each scroll widget maintains its own independent scroll position (managed internally by the node).
Tracking Scroll Position for UI Display
// Use local variables to capture scroll state for display
int scrollPosition = 0;
int totalContent = 0;
ctx.VStack(v => [
v.Text($"Viewing: {scrollPosition + 1} - {Math.Min(scrollPosition + 10, totalContent)} of {totalContent}"),
v.VScroll(
inner => items.Select(item => inner.Text(item)).ToArray()
).OnScroll(args => {
scrollPosition = args.Offset;
totalContent = args.ContentSize;
})
])2
3
4
5
6
7
8
9
10
11
12
13
Related Widgets
- List - Selectable list with built-in scrolling
- VStack/HStack - Layout containers for scroll content
- Border - Often combined with scroll for visual boundaries
- TextBox - Input widget with internal scrolling