Skip to content

ButtonWidget

An interactive button that responds to Enter, Space, or mouse clicks.

Buttons are focusable widgets that provide visual feedback when focused and can trigger actions when activated. They're the primary way to let users perform actions in your terminal UI.

Basic Usage

Create buttons using the fluent API and handle clicks with OnClick:

csharp

Navigation

Use Tab to move focus between buttons, and Enter or Space to activate the focused button. Mouse clicks also work in supported terminals.

Click Handlers

The OnClick method accepts both synchronous and asynchronous handlers.

Synchronous Handler

For simple state updates, use a synchronous handler:

csharp
v.Button("Save").OnClick(_ => document.Save())

The handler receives ButtonClickedEventArgs with access to:

  • Widget - The source ButtonWidget
  • Node - The underlying ButtonNode
  • Context - Access to the application context for navigation, stop requests, etc.

Asynchronous Handler

Hex1b also supports async handlers for when you need to call async APIs:

csharp
v.Button("Fetch").OnClick(async _ => {
    var data = await httpClient.GetStringAsync(url);
    state.Data = data;
})

Render Loop Blocking

Click handlers execute within the render loop. While your async handler awaits, the UI cannot update—no re-renders, no input processing. For quick async calls (like a single HTTP request), this is usually acceptable. For longer operations, use the background work pattern shown below.

Background Work Pattern

For operations that take noticeable time, trigger the work from your state object and use app.Invalidate() to request re-renders as progress updates:

csharp

Key points in this pattern:

  1. Fire and forget: The click handler calls StartLoading() synchronously—it doesn't await the background work
  2. State owns the work: The LoaderState class manages the async operation internally
  3. Explicit invalidation: Call app.Invalidate() whenever state changes to trigger a re-render
  4. UI stays responsive: The render loop continues while work happens in the background

When to Use Each Approach

  • Synchronous: Simple state updates (incrementing counters, toggling flags)
  • Async handler: Quick async calls where brief blocking is acceptable (single API call)
  • Background work: Long-running operations, multi-step processes, or anything needing progress updates

Counter Example

Here's a more complete example showing multiple buttons controlling shared state:

csharp

Focus Behavior

Buttons visually indicate their focus state:

StateAppearance
Unfocused[ Label ]
FocusedHighlighted with theme colors
csharp

The focused button has a distinct background color (configurable via theming) to make it clear which button will be activated when pressing Enter or Space.

Focus Navigation

  • Tab - Move focus to the next focusable widget
  • Shift+Tab - Move focus to the previous focusable widget
  • Enter or Space - Activate the focused button
  • Mouse click - Focus and activate the button

Theming

Customize button appearance using theme elements:

csharp
using Hex1b;
using Hex1b.Theming;

var theme = new Hex1bTheme("Custom")
    .Set(ButtonTheme.ForegroundColor, Hex1bColor.White)
    .Set(ButtonTheme.BackgroundColor, Hex1bColor.Blue)
    .Set(ButtonTheme.FocusedForegroundColor, Hex1bColor.Black)
    .Set(ButtonTheme.FocusedBackgroundColor, Hex1bColor.Yellow)
    .Set(ButtonTheme.LeftBracket, "< ")
    .Set(ButtonTheme.RightBracket, " >");

await using var terminal = Hex1bTerminal.CreateBuilder()
    .WithHex1bApp((app, options) =>
    {
        options.Theme = theme;
        return ctx => ctx.Button("Themed Button");
    })
    .Build();

await terminal.RunAsync();

Available Theme Elements

ElementTypeDefaultDescription
ForegroundColorHex1bColorDefaultText color when unfocused
BackgroundColorHex1bColorDefaultBackground when unfocused
FocusedForegroundColorHex1bColorBlackText color when focused
FocusedBackgroundColorHex1bColorWhiteBackground when focused
LeftBracketstring"[ "Left bracket decoration
RightBracketstring" ]"Right bracket decoration
MinimumWidthint10Minimum button width

Input Bindings

Buttons automatically register these input bindings when a click handler is set:

InputAction
EnterActivate button
SpaceActivate button
Left mouse clickActivate button

You can add additional bindings using the standard input binding API:

csharp
v.Button("Save")
    .OnClick(_ => Save())
    .WithInputBindings(bindings => bindings
        .Ctrl().Key(Hex1bKey.S).Action(() => Save()))

Released under the MIT License.