Skip to content

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:

csharp

Keyboard 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():

csharp

The 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:

csharp

ScrollChangedEventArgs Properties

PropertyTypeDescription
OffsetintCurrent scroll offset after the change
PreviousOffsetintScroll offset before the change
ContentSizeintTotal size of content in characters
ViewportSizeintSize of visible viewport in characters
MaxOffsetintMaximum scroll offset (computed)
IsScrollableboolWhether content exceeds viewport
ProgressdoubleScroll position as 0.0-1.0 value
IsAtStartboolTrue when scrolled to the beginning
IsAtEndboolTrue when scrolled to the end

Tracking Scroll Position

Display the current scroll position in your UI:

csharp

Infinite Scroll

Load more content when the user scrolls near the end:

csharp

Scrollbar Visibility

Control whether the scrollbar is displayed:

csharp

Set showScrollbar: false to hide the scrollbar. The content remains scrollable via keyboard, but no visual indicator appears.

csharp
// With scrollbar (default)
ctx.VScroll(v => [...])

// Without scrollbar
ctx.VScroll(v => [...], showScrollbar: false)

Keyboard Shortcuts

When the scroll widget is focused, these keys control scrolling:

KeyAction
Scroll up one line (vertical)
Scroll down one line (vertical)
Scroll left one column (horizontal)
Scroll right one column (horizontal)
PgUpScroll up one page
PgDnScroll down one page
HomeJump to start
EndJump 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
csharp
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(_ => { /* ... */ })
    ]
)

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:

csharp
// 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 width

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:

csharp
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();

Available Theme Elements

ElementTypeDefaultDescription
VerticalThumbCharacterstringCharacter for vertical scrollbar thumb
VerticalTrackCharacterstringCharacter for vertical scrollbar track
HorizontalThumbCharacterstringCharacter for horizontal scrollbar thumb
HorizontalTrackCharacterstringCharacter for horizontal scrollbar track
ThumbColorHex1bColorGrayColor of scrollbar thumb
FocusedThumbColorHex1bColorWhiteColor of thumb when scroll widget is focused
TrackColorHex1bColorDarkGrayColor of scrollbar track
UpArrowCharacterstringUp arrow for vertical scrollbar
DownArrowCharacterstringDown arrow for vertical scrollbar
LeftArrowCharacterstringLeft arrow for horizontal scrollbar
RightArrowCharacterstringRight arrow for horizontal scrollbar

Common Patterns

Scrollable List of Items

csharp
ctx.VScroll(
    v => items.Select(item => v.Text(item)).ToArray()
)

Scrollable Text Content

csharp
var lines = File.ReadAllLines("document.txt");
ctx.VScroll(
    v => lines.Select(line => v.Text(line)).ToArray()
)

Nested Scrolling

csharp
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)
])

Each scroll widget maintains its own independent scroll position (managed internally by the node).

Tracking Scroll Position for UI Display

csharp
// 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;
    })
])
  • 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

Released under the MIT License.