tui-skeleton
Animated skeleton loading widgets for Ratatui.
Placeholder widgets that pulse, sweep, or shimmer while data loads. All widgets are stateless — pass elapsed_ms from your event loop and the animation state is computed purely from the timestamp.
Widgets
| Widget | Description |
|---|---|
SkeletonBlock |
Solid filled rectangle — the atomic unit |
SkeletonTable |
Rows with column separators and zebra striping |
SkeletonList |
Short spaced items with ragged edges (menu/sidebar) |
SkeletonText |
Paragraph simulation with varying line widths |
SkeletonBarChart |
Vertical bars of varying height |
SkeletonHBarChart |
Horizontal bars of varying length |
SkeletonKvTable |
Key-value pairs (properties/detail panel) |
SkeletonStreamingText |
Typewriter-style chat text filling over time |
SkeletonLineChart |
Braille line chart with overlapping wave traces |
Installation
Usage
use Color;
use ;
let widget = new
.mode
.base
.highlight;
All widgets share the same builder pattern:
use Constraint;
use ;
// Table with 3 columns
let table = new
.columns
.rows
.zebra;
// List (short spaced items)
let list = new
.items;
// Paragraph placeholder
let text = new
.line_widths;
Render conditionally based on your application state:
if data.is_loading else
Animation Modes
| Mode | Cycle | Pattern |
|---|---|---|
| Breathe (default) | 5s | Uniform pulse — subtle, passive loading indicator |
| Sweep | 2.8s | Traveling highlight left-to-right with cosine falloff |
| Plasma | 4s | Dual sine-wave interference for organic shifting patterns |
Colors
All widgets accept base and highlight colors for the interpolation endpoints:
base— dim resting state (default:DarkGray)highlight— peak brightness (default:Gray)
Defaults work on both dark and light terminals. Override to match your theme:
use Color;
use SkeletonBlock;
// Dark theme
let dark = new
.base
.highlight;
// Light theme
let light = new
.base
.highlight;
Adaptive Tick Rate
Skeleton animations look best at ~20 FPS. The crate exports recommended intervals:
use ;
// TICK_ANIMATED = 50ms (20 FPS)
// TICK_IDLE = 200ms (5 FPS)
The recommended pattern:
- Track whether any skeleton is currently visible
- Use
TICK_ANIMATEDwhen skeletons are on screen - Revert to
TICK_IDLEwhen all data has loaded
Builder Methods
All widgets support:
| Method | Default | Description |
|---|---|---|
mode(AnimationMode) |
Breathe |
Animation style |
base(impl Into<Color>) |
DarkGray |
Dim resting color |
highlight(impl Into<Color>) |
Gray |
Peak brightness color |
block(Block) |
None |
Optional border container |
Shape-specific:
| Widget | Method | Default | Description |
|---|---|---|---|
SkeletonTable |
rows(u16) |
5 |
Number of visible rows |
SkeletonTable |
columns(&[Constraint]) |
[] |
Column width constraints |
SkeletonTable |
zebra(bool) |
true |
Alternating row brightness |
SkeletonList |
items(u16) |
5 |
Number of list items |
SkeletonList |
widths(&[f32]) |
built-in pattern | Per-item width fractions (cycles) |
SkeletonText |
line_widths(&[f32]) |
[1.0, 1.0, 0.8, 1.0, 0.6] |
Per-line width fractions (cycles) |
SkeletonBarChart |
bars(u16) |
6 |
Number of vertical bars |
SkeletonBarChart |
bar_width(u16) |
3 |
Width of each bar in cells |
SkeletonBarChart |
heights(&[f32]) |
built-in pattern | Per-bar height fractions (cycles) |
SkeletonHBarChart |
bars(u16) |
5 |
Number of horizontal bars |
SkeletonHBarChart |
bar_height(u16) |
1 |
Height of each bar in rows |
SkeletonHBarChart |
widths(&[f32]) |
built-in pattern | Per-bar width fractions (cycles) |
SkeletonKvTable |
pairs(u16) |
5 |
Number of key-value pairs |
SkeletonKvTable |
key_width(u16) |
12 |
Fixed width of the key column |
SkeletonKvTable |
value_widths(&[f32]) |
built-in pattern | Per-pair value width fractions (cycles) |
SkeletonStreamingText |
lines(u16) |
5 |
Total lines to fill |
SkeletonStreamingText |
duration_ms(u64) |
3000 |
Milliseconds to complete the fill |
SkeletonStreamingText |
repeat(bool) |
false |
Loop the fill cycle |
SkeletonStreamingText |
line_widths(&[f32]) |
built-in pattern | Per-line width fractions (cycles, capped at 95%) |
SkeletonLineChart |
lines(u16) |
2 |
Number of overlapping wave traces |
Examples
Interactive demo
All widget types in a 4×2 grid. Press m to cycle animation modes, q to quit.
Widget pantry
Browse every widget, animation mode, and realistic use-case pane with tui-pantry:
License
Dual licensed under MIT or Apache 2.0.
Contributing
Contributions are welcome. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this work by you shall be dual licensed as above, without any additional terms or conditions.
See CONTRIBUTING.md for guidelines.