Controls Reference

SharpConsoleUI provides 41 built-in UI controls for building rich console applications.

New to SharpConsoleUI? Start with the Tutorials — step-by-step guides that build real apps from scratch.

Table of Contents

Overview

All controls implement the IWindowControl interface and can be added to windows. Interactive controls implement additional interfaces like IInteractiveControl, IFocusableControl, and IMouseAwareControl.

Common Control Properties

All controls support:

  • Name - Unique identifier for FindControl<T>(name) lookups
  • Visible - Show/hide control
  • Container - Reference to parent container
  • Tag - Store custom data
  • Layout properties (Width, Margin, Alignment, StickyPosition)
  • Role / Outline - Available on controls implementing IRoleableControl. Apply a semantic Control Role (Primary, Success, Danger, …) so the control's colors come from the theme's palette instead of being set by hand. Role.Default (the default) leaves color resolution unchanged. Most controls implement IRoleableControl; a few non-themed ones (Canvas, Image, Video, Html, …) do not and have no Role/Outline.

Creating Your Own Control

Need something the built-in controls don't cover? There are two ways to build one, and a step-by-step tutorial for each. Reach for composition first — it's simpler and covers most cases.

  • Compose existing controls — wrap a grid, labels, buttons, etc. into a reusable unit. No custom rendering, no IWindowControl plumbing. Start here. → Contributor Tutorial 1: Composite Controls

  • Write a primitive from scratch — a control that paints its own cells (a gauge, a badge, a sparkline). You derive from BaseControl and override its four abstract/virtual layout members: ContentWidth, GetLogicalContentSize(), MeasureDOM(LayoutConstraints) → LayoutSize, and PaintDOM(...). The tutorial builds a BadgeControl end to end. → Contributor Tutorial 2: Adding a Control

Before hand-rolling a primitive, know these two things — they save the most time:

  • Don't parse markup yourself. The framework already turns [red]…[/] tags into colored runs. Host or compose a MarkupControl for text, or call SharpConsoleUI.Parsing.MarkupParser if you paint directly. Writing raw markup strings straight into buffer cells renders the literal [red] tags on screen — the tags must be parsed to runs first. See Markup Syntax.
  • MeasureDOM and PaintDOM are not on IWindowControl. Both come from the IDOMPaintable contract, which BaseControl implements — that's why deriving from BaseControl is the normal path. See the Interfaces section below for the exact signatures.

For the bigger picture of how paints, layout, and the character buffer fit together, see the DOM Layout System and Rendering Pipeline.

Basic Input Controls

Controls for user input and interaction.

Control Description Details
ButtonControl Clickable button with text Click events, keyboard/mouse support
CheckboxControl Toggle checkbox with label Checked/unchecked state, change events
DatePickerControl Locale-aware date picker Segmented editing, calendar popup, min/max dates
PromptControl Text input, single-line or wrapping Enter key events, optional multiline with grow-to-fit, placeholder, max length, read-only, history, tab completion
TimePickerControl Locale-aware time picker 12h/24h modes, seconds toggle, min/max times
MultilineEditControl Multi-line text editor Syntax highlighting (13 built-in languages via SyntaxHighlighters.For(...)), pluggable gutter, find/replace, undo/redo, word wrap
SliderControl Value slider with thumb Horizontal/vertical, step/large-step, keyboard/mouse drag
RangeSliderControl Dual-thumb range slider MinRange enforcement, tab to switch thumbs, range events
FormControl Labeled-input form Two-column grid (label | editor), typed field overloads (text/multiline/checkbox/dropdown/radio/slider), custom AddField, sections with collapse, row packing, validation, GetValues/Submit/Submitted, declarative XML loader

Selection Controls

Controls for selecting items from lists or hierarchies.

Control Description Details
ListControl Scrollable list with selection Single selection, item activation, keyboard navigation
TableControl Interactive data grid Virtual data, sorting, filtering (AND/OR), inline editing, multi-select, cell navigation, scrollbars
TreeControl Hierarchical tree view Expand/collapse nodes, selection, keyboard navigation
DropdownControl Dropdown selection list Click to expand, keyboard navigation, portal rendering
RadioControl Single-select radio group Typed RadioGroup<T> coordination, Required/AllowDeselect policies, label wrap, cross-layout grouping
MenuControl Menu bar with dropdowns Horizontal/vertical menus, submenus, separators, keyboard shortcuts

Display Controls

Controls for displaying formatted content.

Control Description Details
MarkupControl Rich text with markup Colors, bold, italic, clickable & keyboard-navigable links ([link=url]); renders Markdown (incl. links) via the [markdown] tag, optional border/header
HtmlControl HTML content renderer Parse & render HTML with images, links, tables, keyboard navigation
FigleControl ASCII art text (Figlet) Large stylized text, multiple fonts
ChatTranscriptControl Agent/chat transcript Role-tagged messages (User/Assistant/System/Tool/Error), token-by-token streaming, collapsible tool messages, thinking indicator, gradient headers, alpha bubbles
LogViewerControl Log message viewer Auto-scroll, filtering, severity colors
SpectreRenderableControl Wrapper for Spectre widgets Display Tables, Trees, Panels, Charts, etc.
PanelControl Bordered container panel Hosts child controls (a non-collapsible CollapsiblePanel); headers, border styles, padding, mouse. For bordered text, use MarkupControl with .WithBorder().
RuleControl Horizontal rule/separator Optional title with alignment, colors, border styles; doubles as an inline progress bar (SetProgress/SetIndeterminate). Backs both Controls.Rule(title) and Controls.Separator()
SparklineControl Time-series sparkline graph Block, braille, or bidirectional modes; borders; titles
LineGraphControl Multi-series line graph Braille and ASCII rendering modes, gradients, Y-axis labels, live updates
BarGraphControl Horizontal bar graph Gradient color thresholds, labels, value display
ProgressBarControl Task progress indicator Determinate fill with percentage, or indeterminate pulsing animation
SpinnerControl Animated indeterminate-progress spinner Preset styles + custom frames, per-frame markup, auto-animates via the animation manager. Also available as the inline [spinner] markup tag.

Drawing Controls

Controls for custom graphics and free-form drawing.

Control Description Details
CanvasControl Free-form drawing surface 30+ drawing primitives, retained & immediate modes, thread-safe async painting
ImageControl Image display with Kitty graphics Full-resolution via Kitty/WezTerm/Ghostty with half-block fallback; PNG/JPEG/BMP/GIF/WebP/TIFF; async loading
VideoControl Terminal video player Kitty graphics + half-block/ASCII/braille fallbacks (auto-detected); FFmpeg decode; overlay bar; dynamic resize; looping

Layout Controls

Controls for organizing other controls.

Control Description Details
ColumnContainer Vertical stack container Stack controls vertically, padding, alignment
ScrollablePanelControl Scrollable content area Vertical scrolling, contains multiple controls
HorizontalGridControl Multi-column layout Variable-width columns, alignment, splitters
GridControl WinUI-style 2D grid Fixed/Auto/Star rows & columns, row/col spans, gaps, per-cell styling, any control per cell
FlowControl Renders a flow inline in a region Embeds Flow.Run/Flow.Wizard in a pane (vs. a modal); idle/done placeholder; normal focus scope
WizardControl Runs a multi-step wizard inline A FlowControl named/presetted for wizards (the discoverable door); wizard.Run(Flow.Wizard<T>()...); inline, not modal
HorizontalSplitterControl Draggable horizontal divider Resizes the control above against the one below; mouse drag + Up/Down (Shift for 5-row jumps), min-height floors, SplitterMoved
SplitterControl Vertical column divider Internal to HorizontalGridControl — created by AddSplitter/AddSplitterBefore. For grid splitters use GridControl
TabControl Multi-page tab container Tab headers, keyboard/mouse switching, state preservation
CollapsiblePanel Click-to-expand container Borderless/bordered header, markup title, custom icons, MaxContentHeight, IControlHost. Can also serve as a plain, non-collapsible panel hosting any control via .NonCollapsible() / .HideHeader()
NavigationView Sidebar navigation + content area WinUI-inspired nav pane, responsive display modes (Expanded/Compact/Minimal), content factories, gradient-transparent
ToolbarControl Horizontal button toolbar Auto-height, wrapping, separator lines, content padding, Tab navigation
StatusBarControl Three-zone status bar Left/center/right zones, clickable items, shortcut hints, above line separator
SeparatorControl Vertical separator line Non-interactive single vertical line (Controls.VerticalSeparator()); placed automatically by ToolbarControl and NavigationView. Documented in RuleControl
PortalContentContainer Portal overlay container Host child controls in portal overlays, mouse/keyboard routing, focus tracking

Utility Controls

Special-purpose controls.

Control Description Details
TerminalControl PTY-backed terminal emulator Full xterm-256color, keyboard/mouse passthrough, auto-resize. Linux only.

Interfaces

Controls implement these interfaces based on their capabilities:

IWindowControl (Base Interface)

All controls implement this interface. It defines identity, layout, and sizing — not painting (see the note below):

public interface IWindowControl : IDisposable
{
    // Identity
    IContainer? Container { get; set; }
    string? Name { get; set; }
    object? Tag { get; set; }
    bool Visible { get; set; }

    // Layout & sizing
    int? ContentWidth { get; }                    // intrinsic width of the content, or null
    HorizontalAlignment HorizontalAlignment { get; set; }
    VerticalAlignment VerticalAlignment { get; set; }
    Margin Margin { get; set; }
    StickyPosition StickyPosition { get; set; }
    int? Width { get; set; }
    int? Height { get; set; }
    int ActualX { get; }                          // where it was last rendered
    int ActualY { get; }
    int ActualWidth { get; }
    int ActualHeight { get; }

    // Intrinsic content size — returns System.Drawing.Size
    Size GetLogicalContentSize();

    // Invalidation (Repaint vs Relayout)
    void Invalidate(Invalidation work);
    void Invalidate();                            // default impl → Invalidate(Relayout)
    void Invalidate(bool redrawAll);              // default impl → Relayout / Repaint
}

Where are measure and paint? IWindowControl has neither. Both come from the IDOMPaintable contract (SharpConsoleUI/Layout/IDOMPaintable.cs), which BaseControl implements and re-declares as abstract members you override:

public interface IDOMPaintable
{
    LayoutSize MeasureDOM(LayoutConstraints constraints);
    void PaintDOM(CharacterBuffer buffer, LayoutRect bounds, LayoutRect clipRect,
                  Color defaultForeground, Color defaultBackground);
}

(IDOMMeasurable declares MeasureDOM alone, for controls that measure but don't paint.) This is why the normal way to write a custom primitive is to derive from BaseControl and override MeasureDOM and PaintDOM — see Creating Your Own Control and Contributor Tutorial 2.

Namespaces: IWindowControl, IContainer, Margin, StickyPosition, BaseControlSharpConsoleUI.Controls; HorizontalAlignment, VerticalAlignment, CharacterBuffer, LayoutRect, LayoutSize, LayoutConstraints, IDOMPaintable, IDOMMeasurableSharpConsoleUI.Layout; Invalidation, ColorSharpConsoleUI; MarkupParserSharpConsoleUI.Parsing; Size is System.Drawing.Size (not a SharpConsoleUI type).

IInteractiveControl

Controls that handle keyboard input:

public interface IInteractiveControl : IWindowControl
{
    bool IsEnabled { get; set; }
    bool ProcessKey(KeyEventArgs e);
}

Implemented by: Button, Checkbox, Prompt, MultilineEdit, List, Tree, Table, Dropdown, Menu, Canvas, Grid

IFocusableControl

Controls that can receive keyboard focus:

public interface IFocusableControl : IInteractiveControl
{
    bool HasFocus { get; }
    bool CanReceiveFocus { get; }
    event EventHandler? GotFocus;
    event EventHandler? LostFocus;
    void SetFocus();
}

Implemented by: Button, Checkbox, Prompt, MultilineEdit, List, Tree, Table, Dropdown, Canvas, Grid

IMouseAwareControl

Controls that handle mouse events:

public interface IMouseAwareControl : IWindowControl
{
    bool WantsMouseEvents { get; }
    bool CanFocusWithMouse { get; }
    event EventHandler<MouseEventArgs>? MouseClick;
    event EventHandler<MouseEventArgs>? MouseEnter;
    event EventHandler<MouseEventArgs>? MouseLeave;
    event EventHandler<MouseEventArgs>? MouseMove;
    void ProcessMouseEvent(MouseEventArgs e);
}

Implemented by: Button, List, Tree, Table, Dropdown, Menu, Toolbar, ScrollablePanel, Canvas, Grid

IContainer

The container surface used by child controls for rendering — colors, dirty tracking, and invalidation. It is not a child-mutation API; for that, see IControlHost below.

public interface IContainer
{
    Color BackgroundColor { get; set; }
    Color ForegroundColor { get; set; }
    ConsoleWindowSystem? GetConsoleWindowSystem { get; }
    void Invalidate(Invalidation work, IWindowControl? callerControl = null);
    int? GetVisibleHeightForControl(IWindowControl control);
}

Implemented by: ColumnContainer, ScrollablePanelControl, HorizontalGridControl, GridControl, NavigationView, Window, and other containers.

IControlHost

Capability interface for containers whose children are a flat list of IWindowControl. Lets you add, remove, clear, and enumerate children without binding to a concrete container type.

public interface IControlHost
{
    void AddControl(IWindowControl control);
    void RemoveControl(IWindowControl control);
    void ClearControls();
    IReadOnlyList<IWindowControl> Children { get; }
}

Implemented by: ScrollablePanelControl, ColumnContainer, CollapsiblePanel, GridControl, Window.

Not implemented by TabControl (tabs are title-keyed pages), MenuControl (children are MenuItem, not IWindowControl), ToolbarControl, or NavigationView — their child models are not a flat IWindowControl list, so forcing the contract would mean throwing NotSupportedException.

// Write once against the capability, reuse anywhere.
void PopulateForm(IControlHost host)
{
    host.AddControl(Controls.Label("Name:"));
    host.AddControl(Controls.Prompt().Build());
}

PopulateForm(scrollablePanel);
PopulateForm(column);
PopulateForm(window);

ColumnContainer and Window keep their existing native names (AddContent/Contents on ColumnContainer; RemoveContent/GetControls() on Window); the IControlHost members are implemented via explicit interface forwarding so the public APIs are unchanged.

Quick Reference

Creating Controls

// Using builders (recommended)
var button = Controls.Button("Click Me")
    .WithWidth(20)
    .OnClick((s, e, w) => { })
    .Build();

// Using constructors
var button = new ButtonControl
{
    Text = "Click Me",
    Width = 20
};
button.OnClick += (s, e) => { };

// Using static helpers
var label = Controls.Label("Simple text");
var header = Controls.Header("Title");

// Canvas control
var canvas = new CanvasControl(80, 24);

Adding to Windows

window.AddControl(control);

Finding Controls by Name

// Name a control
window.AddControl(
    Controls.Prompt("Name:")
        .WithName("nameInput")
        .Build()
);

// Find it later
var input = window.FindControl<PromptControl>("nameInput");
if (input != null)
{
    string text = input.Text;
}

Common Patterns

Input Form

window.AddControl(Controls.Header("Contact Form"));
window.AddControl(Controls.Prompt("Name:").WithName("name").Build());
window.AddControl(Controls.Prompt("Email:").WithName("email").Build());
window.AddControl(Controls.Button("Submit")
    .OnClick((s, e, w) =>
    {
        var name = w.FindControl<PromptControl>("name")?.Text;
        var email = w.FindControl<PromptControl>("email")?.Text;
        // Process form...
    })
    .Build());

Data Display

var list = Controls.List()
    .AddItem("Item 1")
    .AddItem("Item 2")
    .AddItem("Item 3")
    .OnItemActivated((s, item, w) =>
    {
        windowSystem.NotificationStateService.ShowNotification(
            "Selected", item.Text, NotificationSeverity.Info);
    })
    .Build();

window.AddControl(list);

Layout

var grid = Controls.HorizontalGrid()
    .WithAlignment(HorizontalAlignment.Stretch)
    .Column(col => col.Add(Controls.Label("Left")))
    .Column(col => col.Add(Controls.Label("Center")))
    .Column(col => col.Add(Controls.Label("Right")))
    .Build();

window.AddControl(grid);

Next Steps

Browse detailed documentation for specific controls:

Essential Controls

Input Controls

Layout & Status Controls

Advanced Controls

Cross-Cutting Features

  • Syntax Highlighting - 13 built-in highlighters + registry, used by MultilineEditControl and Markdown code blocks
  • Markup Syntax - Colors, decorations, spinners, and the [markdown] tag

Back to Main Documentation