Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Loading

Indeterminate loaders, skeleton placeholders, and dimming overlays for async work.

Loader

An animated progress indicator in one of 20 styles. Every loader takes .now(Instant) for real-time animation or .elapsed(secs) for deterministic headless rendering. Single-row styles are vertically centered in their area; multi-row scenes fill every row you give them.

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer, now: Instant) {
Loader::new(LoaderStyle::Scanner).now(now).render(area, buf);
}
fn main() {}

Bars

Animated progress bars that use one row, centered vertically.

StyleAppearancelabelcolorcolor2speed
ScannerBright cell with fading tail sweeping back and forthnoyesnoyes
CometTail traveling one way and wrappingnoyesnoyes
SweepMaterial indeterminate: eased segment sliding acrossnoyesnoyes
FillDrainBar fills from left, then drains from leftnoyesnoyes
PulseWhole bar breathesnoyesnoyes
StripesBarber-pole stripes marching rightnoyesyesyes
RainbowHue-cycling rainbow flowing along the barnononoyes
SnakeThree dots chasing along a dotted tracknoyesyesyes
ChaseLED chase: one lit segment with dim trailnoyesnoyes
Blocks▰▰▰▱▱▱ filling and emptyingnoyesnoyes
WaveTraveling sine wave of eighth-blocksnoyesyesyes
BounceBall bouncing between bracketsnoyesnoyes
PingExpanding rings (((●)))noyesnoyes
HeartbeatScrolling ECG trace with glowing spikenoyesyesyes

All bar styles ignore label (the text is drawn separately to the left of the loader area). color defaults to $primary, color2 defaults to $accent. When given one row, they render normally. When given more than one row, the animation is vertically centered.

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer, now: Instant) {
Loader::new(LoaderStyle::Sweep).color(Rgb(100, 150, 255)).speed(1.5).now(now).render(area, buf);
}
fn main() {}

Text

The label is the animated content. These styles use one row.

StyleAppearancelabelcolorcolor2speed
Ellipsislabel, label., label.., label...yesyesnoyes
ShimmerLabel with sweeping highlight bandyesyesyesyes
TypewriterLabel typed out with cursor, held, cleared, repeatedyesyesnoyes

For textual styles, the label is required (the default is an empty string, which renders nothing). color is the text color, color2 is the highlight color (Shimmer only). When given more than one row, the text is vertically centered.

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer, now: Instant) {
Loader::new(LoaderStyle::Typewriter).label("Indexing workspace").now(now).render(area, buf);
}
fn main() {}

Scenes

Full-area animations that use every row you give them.

StyleAppearancelabelcolorcolor2speed
EqualizerBouncing spectrum barsnoyesyesyes
RainMatrix rainnoyesnoyes
RadarRadar sweep over a dot field with blipsnoyesyesyes

All scene styles ignore label. color is the main color, color2 is the accent color. These styles need at least 3 rows to be recognizable. When given only one row, they attempt to render but the result is a degraded horizontal slice of the animation (Rain becomes a flickering line, Radar becomes a scanning line, Equalizer becomes a flat bar).

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer, now: Instant) {
Loader::new(LoaderStyle::Radar).color(Rgb(0, 200, 100)).color2(Rgb(255, 200, 0)).now(now).render(area, buf);
}
fn main() {}

Builder options

MethodEffect
label(s)Text left of the bar; for textual styles this is the animated text
color(rgb)Main color (default $primary)
color2(rgb)Secondary color for two-tone styles (default $accent)
speed(f)Playback rate; 1.0 is the designed speed
now(Instant)Animation phase from app clock
elapsed(f32)Explicit elapsed seconds for deterministic rendering
theme(&Theme)Override theme

Skeleton

Painted placeholder shapes with a diagonal shimmer band. Use them to reserve space while content loads.

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer, now: Instant) {
Skeleton::new().shape(SkeletonShape::Card).now(now).render(area, buf);
}
fn main() {}

Shapes

ShapeLayout
TextOne bar per entry in .lines([widths]) (cells), a blank row between when there’s room
CardHero image block on top, then a title and two body lines
AvatarAvatar block with a name and handle beside it
ListStacked avatar rows: a list waiting for its items
TableHeader cells and rows of column cells (2-4 columns depending on width)
ChartBars of varying height along a baseline

The default shape is Text with line widths [60, 45, 50] cells. For Text, pass custom widths with .lines(&[80, 70, 85]). Other shapes ignore .lines() and lay out based on the area size.

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer, now: Instant) {
Skeleton::new().shape(SkeletonShape::List).now(now).render(area, buf);
}
fn main() {}

The shimmer band sweeps diagonally across the skeleton. All shapes respect .now(Instant) or .elapsed(secs) for animation phase.

LoadingOverlay

Dim an area and center a Loader with an optional message over it. Draw this last, over the content it covers.

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer, now: Instant) {
LoadingOverlay::new(Loader::new(LoaderStyle::Sweep)).message("Fetching rows").now(now).render(area, buf);
}
fn main() {}

The overlay dims the existing buffer content by blending each cell’s foreground and background toward the theme background color. The dimming amount is controlled with .dim(f) where 0.0 leaves content untouched and 1.0 hides it completely (default 0.65).

The loader is centered in the area. For single-row loader styles, the .width(cells) option controls the loader width (default 24). Multi-row loaders occupy a fixed centered region.

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer, now: Instant) {
LoadingOverlay::new(Loader::new(LoaderStyle::Scanner).color(Rgb(100, 200, 255)))
    .message("Syncing")
    .dim(0.75)
    .width(32)
    .now(now)
    .render(area, buf);
}
fn main() {}

The message appears below the loader in muted text. When the area is too small (less than 5 rows or 20 columns), the overlay renders the dimming only, skipping the loader and message.

MethodEffect
message(s)Text below the loader
dim(f)Fade strength: 0.0 (untouched) to 1.0 (hidden); default 0.65
width(u16)Loader width for single-row styles; default 24
now(Instant)Animation phase from app clock
elapsed(f32)Explicit elapsed seconds
theme(&Theme)Override theme