Skip to content

Display Widgets (Read-Only)

Text

Renders styled text.

PropTypeDescription
contentimpl Into<String>Constructor - text content
spansimpl IntoIterator<Item = Span>Construct from styled spans
from_ansi&strConstruct from ANSI-escaped string (SGR sequences → styled spans)
styleStyleText style
overflowOverflowClip, Ellipsis, Wrap
widthLengthWidth
heightLengthHeight
rust
Text::new("Hello, World!")
    .style(Style::new().fg(Color::Cyan).bold())
    .overflow(Overflow::Ellipsis)
rust
// Render ANSI-styled output (ls --color, compiler errors, git diff, etc.)
Text::from_ansi("\x1b[31merror\x1b[0m: file not found")

DocumentView

Read-only rich document renderer with pluggable formatting.

Use it for markdown previews, formatted logs, and custom read-only views where display content differs from source text.

PropTypeDescription
valueimpl Into<Arc<str>>Constructor - source text
content_typeArc<str>Optional formatter hint ("markdown", etc.)
formatterimpl ContentFormatterCustom formatting strategy
widthLengthWidth
heightLengthHeight
wrapboolWord-wrap long lines (default: true)
borderboolShow/hide outer border (default: true)
border_styleBorderStyleBorder glyph variant
hover_border_styleBorderStyleBorder variant when hovered
paddingimpl Into<Padding>Inner padding
table_wrapboolWrap table cell text within column width
table_width_modeDocumentTableWidthModeContent (natural) or Fill (stretch to viewport)
table_outer_frameboolShow/hide outer table frame
table_inner_frameboolShow/hide inner table separators
table_cell_paddingu16Horizontal padding inside each table cell
table_border_variantBorderStyleTable border glyph variant (Plain, Rounded, Double, etc.)
table_border_styleStyleStyle for table borders (color/emphasis)
line_numbersboolSource-mapped line-number gutter
line_number_modeDocumentLineNumberModeVisual (visual row index) or Source (source line mapping)
min_line_number_widthu8Minimum line-number gutter digit width
line_number_separatorboolShow/hide built-in line-number separator (" │ ", default: true)
line_number_content_gapu16Empty cells between built-in line numbers and content
line_number_styleStyleStyle override for built-in line-number gutter text
gutter_insetu16Empty cells before the gutter / line numbers
styleStyleBase style
hover_styleStyleHover style
focus_styleStyleFocus chrome style
focus_content_styleStyleText content style when focused
selection_styleStyleSelection style (reserved for selection mode)
highlight_full_widthboolExtend per-line background highlights across full content width
doc_stylesDocumentStylesElement styles (heading/code/link/table/hr/etc.)
code_block_styleStyleShortcut - sets doc_styles.code_block_style
scroll_offsetusizeControlled vertical scroll offset
scroll_to_source_lineusizeScroll-sync target source line
scrollbarboolShow/hide vertical scrollbar
scrollbar_configScrollbarConfigFull scrollbar configuration (variant, gap, thumb, thumb styles)
h_scrollbarboolShow/hide horizontal scrollbar (only when wrap is false)
scroll_wheelboolEnable/disable mouse wheel scrolling (default: true)
focusableboolParticipate in focus traversal; mouse selection and Ctrl+C copy still work when false
on_scrollCallback<ScrollEvent>Scroll callback
on_clickCallback<DocumentClickEvent>Click callback with source-line mapping
on_selectCallback<DocumentSelectEvent>Text selection callback
on_keyKeyHandlerFocused keyboard handler
shared_selection_idArc<str>Group id for cross-DocumentView selection/copy within the same ScrollView
triple_click_modeTripleClickSelectionModeTriple-click selects a visual line or paragraph

DocumentView ships with PlainFormatter by default.

For inline/message-style read-only blocks, wrapped DocumentView now implicitly behaves like height: Length::Auto when all of these are true: default height: Flex(1), wrap: true, scrollbar: false, h_scrollbar: false, and focusable: false. Set .height(...) explicitly when you want viewport-style behavior instead.

When using DocumentView::markdown(), default heading/link/code/table styling is derived from Theme::document. Use .doc_styles(...) or a custom MarkdownFormatter::styles(...) only when you want local overrides.

With feature markdown, you can use MarkdownFormatter:

rust
DocumentView::new("# Hello\n\n| A | B |\n|---|---|\n| 1 | 2 |")
    .markdown()
    .line_numbers(true)
    .wrap(true)

// Compact mode - collapses blank lines between blocks
DocumentView::new(text)
    .markdown_compact(true)

Keyboard scrolling (when focused): arrows, j/k, PageUp/PageDown, Home/End.

Table drag-selection supports rectangular selection by row/column and copies as TSV.

When sibling DocumentView widgets under the same ScrollView share shared_selection_id, linear drag selection can continue across widget boundaries and shared copy concatenates text in visual order with newline separators between document boundaries.

Custom markdown styles

DocumentStyles controls per-element colors. Default values come from Theme::document automatically - only set this when you want widget-local overrides.

rust
// Via DocumentView::doc_styles - applies to any formatter
DocumentView::new(text)
    .markdown()
    .doc_styles(DocumentStyles {
        heading_styles: [
            Style::new().bold().fg(Color::Cyan),   // h1
            Style::new().bold().fg(Color::Blue),   // h2
            Style::new().bold().fg(Color::Green),  // h3
            Style::new().bold(),                   // h4
            Style::new().bold(),                   // h5
            Style::new().bold().dim(),             // h6
        ],
        link_style: Style::new().fg(Color::Blue).underline(),
        code_inline_style: Style::new().fg(Color::Green),
        code_block_style: Style::new().bg(Color::rgb(0x1E, 0x1E, 0x1E)),
        emphasis_style: Style::new().italic(),
        strong_style: Style::new().bold(),
        strikethrough_style: Style::new().strikethrough(),
        blockquote_bar_style: Style::new().fg(Color::DarkGray),
        table_border_style: Style::new().fg(Color::DarkGray),
        table_header_style: Style::new().bold(),
        hr_style: Style::new().fg(Color::DarkGray).dim(),
    });

// Via MarkdownFormatter::styles - same effect, explicit formatter path
DocumentView::new(text)
    .formatter(MarkdownFormatter::default().styles(DocumentStyles {
        strong_style: Style::new().bold().fg(Color::Yellow),
        ..DocumentStyles::default()  // theme fills in the rest automatically
    }));

Syntax highlighting in code blocks (requires feature syntax-syntect)

rust
DocumentView::new(text)
    .markdown()
    .code_syntax_strategy(SyntectStrategy::default().default_theme("One Dark (Atom)"))
// .markdown() already sets this default theme; override here to use a different one

AsciiCanvas

Renders ASCII art as text lines, cell grids, or multi-frame sprite sheets.

Constructors

rust
// Line-based content
AsciiCanvas::new(["Line 1", "Line 2"])

// Cell grid
AsciiCanvas::from_cells(width, height, cells)

// Blank grid for programmatic fill
AsciiCanvas::blank(width, height)

// Generated grid
AsciiCanvas::with_cell_fn(width, height, |x, y| AsciiCanvasCell { ch, fg, bg })

// Multi-frame sprite sheet
AsciiCanvas::from_sequence(Arc::new(frame_sequence))

Frame Sequence API

rust
let seq = Arc::new(FrameSequence::from_json(&json_str).unwrap());

let canvas = AsciiCanvas::from_sequence(seq.clone())
    .frame(0)                            // Select frame by index
    // or: .frame_by_tag("key", "value") // Select frame by tag

FrameSequence::from_json() parses ASCII Motion export format. Supports foreground and background color maps.

Color Remapping

rust
// Unified map (both fg and bg)
let colors = seq.collect_colors();         // All unique colors, fg+bg merged
let canvas = AsciiCanvas::from_sequence(seq)
    .color_map(vec![
        (colors[0], theme.highlight.fg.unwrap_or(Color::White)),
        (colors[1], Color::hex("#3A3A3A")),
    ]);

// Per-channel maps (when same hex appears in both fg and bg)
let fg_colors = seq.collect_fg_colors();   // Unique foreground colors
let bg_colors = seq.collect_bg_colors();   // Unique background colors
let canvas = AsciiCanvas::from_sequence(seq)
    .fg_color_map(vec![(fg_colors[0], Color::White)])
    .bg_color_map(vec![(bg_colors[0], Color::Black)]);

Per-channel maps take precedence over the unified map for their respective channel.

Props

PropTypeDescription
linesVec<String>Constructor - line-based content
styleStyleBase style
backgroundStyleBackground-only style
color_mapVec<(Color, Color)>Unified fg+bg remap
fg_color_mapVec<(Color, Color)>Foreground-only remap
bg_color_mapVec<(Color, Color)>Background-only remap
grid_size(u16, u16)Grid dimensions (must match cells count)
widthLengthWidth
heightLengthHeight

BigText (requires feature big-text)

Large text rendered with ASCII or pixel fonts.

PropTypeDescription
textimpl Into<RichText>Text content or Vec<Span> for multicolor
fontBigTextFontFont choice (see below)
styleStyleBase style (per-span styles override this)
shadowShadowShadow configuration
with_shadowStyleQuick shadow with given style
custom_figletStringCustom .flf FIGlet font content
widthLengthWidth
heightLengthHeight

FIGlet fonts: Standard, Slant, Bloody, Colossal, Roman, SubZero, Poison, Nancyj, SmallPoison, DosRebel, AnsiShadow, Small, CustomFiglet

Pixel fonts: Pixel (8x8 half blocks), PixelBold, Quadrant (2×2 block mapping)

rust
BigText::new("Hello")
    .font(BigTextFont::AnsiShadow)
    .style(Style::new().fg(Color::Cyan))

// Multicolor via spans
BigText::new(vec![
    Span::new("open").fg(Color::Cyan),
    Span::new("code").fg(Color::White),
])
.font(BigTextFont::Standard)

FIGlet smushing does not cross span boundaries in multicolor mode.


Image (requires feature image)

Protocol-aware image rendering.

PropTypeDescription
srcimpl Into<String>Constructor - image file path
bytesArc<[u8]>In-memory image (use Image::from_bytes(...))
fitImageFitContain (default), Crop, Scale
protocolImageProtocolAuto, Kitty, Iterm2, Sixel, Halfblocks
styleStyleContainer style
altStringAlt text shown when protocol fails
playbackImagePlaybackPlaying, Paused
repeatImageRepeatLoop, Once
speed_percentu32Animation speed percentage
widthLengthWidth
heightLengthHeight
rust
Image::new("logo.png")
    .fit(ImageFit::Contain)
    .alt("Company Logo")

// From memory
let bytes: Arc<[u8]> = load_image_bytes();
Image::from_bytes(bytes)
    .protocol(ImageProtocol::Auto)

Animation (GIF, animated WebP, APNG): advance automatically.

  • Small GIFs are preloaded; large GIFs use a bounded worker channel.
  • Controls via playback, repeat, speed_percent.

Environment knobs:

VariableDefaultDescription
TUI_LIPAN_IMAGE_MAX_FPS30Frame rate cap
TUI_LIPAN_IMAGE_MAX_CATCHUP_MS100Frame catch-up window
TUI_LIPAN_IMAGE_AUTO_ANIM_HALF_BLOCKSfalseAllow halfblocks for animations
TUI_LIPAN_IMAGE_ENCODE_WORKERS1Async encoding workers (1–2)
TUI_LIPAN_IMAGE_GIF_PRELOADtrueEager GIF preloading
TUI_LIPAN_IMAGE_GIF_PRELOAD_MAX_BYTES262144Preload size cap
TUI_LIPAN_IMAGE_GIF_PRELOAD_MAX_FRAMES24Preload frame cap
TUI_LIPAN_IMAGE_GIF_PRELOAD_BUDGET_MS16Preload time cap
TUI_LIPAN_IMAGE_GIF_WORKER_QUEUE2Worker queue size (1–4)
TUI_LIPAN_IMAGE_RESIZE_PAUSE_MS180Pause rendering during resize
TUI_LIPAN_IMAGE_LAYOUT_STABILIZE_MS120Pause while layout changes

Sparkline

Minimal inline chart for time-series data.

PropTypeDescription
dataVec<u64>Constructor - data points
variantSparklineVariantBars (default), Braille, Line
minOption<u64>Data minimum (auto if None)
maxOption<u64>Data maximum (auto if None)
chart_heightu16Multi-row height for Bars/Braille/Line
mirror_xboolReverse sample order (time axis)
mirror_yboolFlip vertical direction
max_pointsOption<usize>Cap rendered width (enables downsampling)
aggregationSparklineAggregationAverage, Min, Max, First, Last
zero_policySparklineZeroPolicyMinGlyph for baseline on zeros
gradientColorGradientMap values → RGB colors
height_gradientColorGradientMap row position → RGB colors
gradient_rangeGradientRangeNormalize gradient range
styleStyleBase style
rising_styleStyleStyle for rising values
falling_styleStyleStyle for falling values
overflowOverflowDefault: Ellipsis; use ClipStart for live charts
widthLengthWidth
heightLengthHeight
rust
Sparkline::new(metrics.clone())
    .variant(SparklineVariant::Braille)
    .chart_height(4)
    .overflow(Overflow::ClipStart)   // Keep newest data visible
    .gradient(ColorGradient::new(vec![
        (0.0, Color::Green),
        (1.0, Color::Red),
    ]))

Chart

Multi-series chart with axes, legend, thresholds, and viewport windowing.

PropTypeDescription
seriesVec<ChartSeries>Data series
x_axisChartAxisX axis configuration
y_axisChartAxisY axis configuration
thresholdsVec<ChartThreshold>Horizontal threshold lines
viewport_startOption<usize>Start sample index for zoom
viewport_lenOption<usize>Number of samples to show
show_legendboolShow series legend
show_gridboolShow background grid
legend_styleStyleLegend style
grid_styleStyleGrid style
legend_separatorcharLegend entry separator
borderboolDraw border
border_styleBorderStyleBorder appearance
paddingimpl Into<Padding>Inner padding
widthLengthWidth
heightLengthHeight
rust
let series = ChartSeries::new("CPU", cpu_data)
    .mode(ChartSeriesMode::Line)
    .style(Style::new().fg(Color::Cyan));

Chart::new()
    .series(vec![series])
    .show_legend(true)
    .show_grid(true)
    .thresholds(vec![ChartThreshold::new(80.0).style(Style::new().fg(Color::Red))])

Heatmap

2D matrix visualization with gradient-colored cells or glyphs.

PropTypeDescription
dataVec<Vec<f64>>Constructor - 2D matrix of values
row_labelsVec<impl Into<Arc<str>>>Labels on the left side
column_labelsVec<impl Into<Arc<str>>>Labels on top
gradientColorGradientColor gradient for value mapping
range(f64, f64)Explicit min/max for gradient normalization
cell_modeHeatmapCellModeBackground, Glyph(Arc<str>), or GlyphForeground(Arc<str>)
cell_widthu16Character width per cell (default: 4)
gap_xu16Horizontal gap between cells in characters
gap_yu16Vertical gap between heatmap rows in lines
legend_gapu16Horizontal gap between legend markers/swatches
legend_spacingu16Vertical gap between the heatmap grid and legend
legend_widthHeatmapLegendWidthLegend alignment: grid width or full inner width
show_valuesboolDisplay numeric values in cells
show_legendboolShow gradient legend below
styleStyleBase style
label_styleStyleRow/column label style
legend_styleStyleLegend style
paddingimpl Into<Padding>Inner padding
borderboolDraw border
border_styleBorderStyleBorder appearance
widthLengthWidth
heightLengthHeight

Use HeatmapCellMode::Glyph(...) when you want a repeated glyph texture with colored tile backgrounds, or HeatmapCellMode::GlyphForeground(...) when you want only the glyph colored and the background left untouched. Both glyph modes accept strings like " " as well as single characters. gap_x and gap_y work in all modes and make sparse glyph layouts much easier to read. legend_gap separates legend markers from each other, legend_spacing adds space between the heatmap grid and the legend itself, and legend_width(HeatmapLegendWidth::Full) lets the legend ignore the row-label gutter and stretch across the full inner width.

rust
let data = vec![
    vec![10.0, 25.0, 40.0, 55.0],
    vec![20.0, 35.0, 50.0, 65.0],
    vec![30.0, 45.0, 60.0, 75.0],
];

Heatmap::new(data)
    .row_labels(["Low", "Med", "High"])
    .column_labels(["Q1", "Q2", "Q3", "Q4"])
    .gradient(ColorGradient::new(Color::Rgb(60, 179, 113), Color::Rgb(226, 82, 87)))
    .range(0.0, 100.0)
    .cell_mode(HeatmapCellMode::GlyphForeground("".into()))
    .gap_x(1)
    .gap_y(1)
    .legend_gap(1)
    .legend_spacing(1)
    .legend_width(HeatmapLegendWidth::Full)
    .show_legend(true)
    .border(true)

MIT OR Apache-2.0