Skip to main content

textual_rs/
lib.rs

1#![deny(missing_docs)]
2//! textual-rs — a Rust port of the [Textual](https://textual.textualize.io) Python TUI framework.
3//!
4//! Build beautiful terminal UIs in Rust: declare widgets, style with CSS,
5//! react to events, and get a polished result on any terminal.
6//!
7//! # Features
8//!
9//! - **22+ built-in widgets** — buttons, inputs, tables, trees, tabs, markdown, and more
10//! - **CSS styling engine** — TCSS stylesheets with selectors, pseudo-classes, and specificity cascade
11//! - **Theme system** — 7 built-in themes with `$variable` support and lighten/darken modifiers
12//! - **Reactive state** — `Reactive<T>` signals with automatic re-rendering
13//! - **Flexbox & grid layout** — powered by [Taffy](https://github.com/DioxusLabs/taffy)
14//! - **Async workers** — background tasks with progress streaming
15//! - **Headless testing** — `TestApp` + `Pilot` for automated UI tests
16//!
17//! # Quick Start
18//!
19//! Add to your `Cargo.toml`:
20//!
21//! ```toml
22//! [dependencies]
23//! textual-rs = "0.3"
24//! ```
25//!
26//! Create a minimal application:
27//!
28//! ```no_run
29//! use textual_rs::{App, Widget, Label, Header, Footer};
30//! use textual_rs::widget::context::AppContext;
31//! use ratatui::{buffer::Buffer, layout::Rect};
32//!
33//! struct MyScreen;
34//! impl Widget for MyScreen {
35//!     fn widget_type_name(&self) -> &'static str { "MyScreen" }
36//!     fn compose(&self) -> Vec<Box<dyn Widget>> {
37//!         vec![
38//!             Box::new(Header::new("My App")),
39//!             Box::new(Label::new("Hello, world!")),
40//!             Box::new(Footer),
41//!         ]
42//!     }
43//!     fn render(&self, _: &AppContext, _: Rect, _: &mut Buffer) {}
44//! }
45//!
46//! fn main() -> anyhow::Result<()> {
47//!     App::new(|| Box::new(MyScreen)).run()
48//! }
49//! ```
50//!
51//! Add CSS styling with theme variables:
52//!
53//! ```no_run
54//! # use textual_rs::{App, Widget, Label, Header, Footer};
55//! # use textual_rs::widget::context::AppContext;
56//! # use ratatui::{buffer::Buffer, layout::Rect};
57//! # struct MyScreen;
58//! # impl Widget for MyScreen {
59//! #     fn widget_type_name(&self) -> &'static str { "MyScreen" }
60//! #     fn render(&self, _: &AppContext, _: Rect, _: &mut Buffer) {}
61//! # }
62//! let mut app = App::new(|| Box::new(MyScreen))
63//!     .with_css("
64//!         MyScreen { background: $background; color: $foreground; }
65//!         Header { background: $panel; color: $primary; }
66//!     ");
67//! // app.run()?;
68//! ```
69//!
70//! Press **F5** at runtime to cycle through built-in themes (textual-dark,
71//! textual-light, tokyo-night, nord, gruvbox, dracula, catppuccin).
72//! Use [`App::with_theme_cycle_key`] to rebind it.
73//!
74//! See the [User Guide](https://github.com/jabberwock/textual-rs/blob/master/docs/guide.md)
75//! and [CSS Reference](https://github.com/jabberwock/textual-rs/blob/master/docs/css-reference.md)
76//! for full documentation.
77
78pub mod animation;
79pub mod app;
80pub mod canvas;
81pub mod command;
82pub mod hyperlink;
83pub mod css;
84pub mod event;
85pub mod layout;
86pub mod reactive;
87pub mod terminal;
88pub mod testing;
89pub mod widget;
90pub mod worker;
91
92pub use app::App;
93pub use event::AppEvent;
94pub use testing::pilot::Pilot;
95pub use testing::TestApp;
96pub use widget::{Widget, WidgetId};
97pub use hyperlink::{LinkedSpan, LinkedLine};
98// Re-export proc macros — derive macro Widget lives in a separate namespace from the Widget trait,
99// so `pub use textual_rs_macros::Widget` does not conflict with `pub use widget::Widget`.
100pub use command::{CommandPalette, CommandRegistry};
101pub use textual_rs_macros::widget_impl;
102pub use textual_rs_macros::Widget;
103pub use widget::button::{Button, ButtonVariant};
104pub use widget::checkbox::Checkbox;
105pub use widget::collapsible::Collapsible;
106pub use widget::data_table::{ColumnDef, DataTable};
107pub use widget::footer::Footer;
108pub use widget::header::Header;
109pub use widget::input::Input;
110pub use widget::label::Label;
111pub use widget::layout::{Horizontal, Vertical};
112pub use widget::list_view::ListView;
113pub use widget::loading_indicator::LoadingIndicator;
114pub use widget::log::Log;
115pub use widget::markdown::Markdown;
116pub use widget::placeholder::Placeholder;
117pub use widget::progress_bar::ProgressBar;
118pub use widget::radio::{RadioButton, RadioSet};
119pub use widget::rich_log::RichLog;
120pub use widget::scroll_region::{ScrollContent, ScrollRegion};
121pub use widget::scroll_view::ScrollView;
122pub use widget::select::Select;
123pub use widget::sparkline::Sparkline;
124pub use widget::switch::Switch;
125pub use widget::tabs::{TabbedContent, Tabs};
126pub use widget::screen::ModalScreen;
127pub use widget::text_area::TextArea;
128pub use widget::tree_view::{Tree, TreeNode};
129pub use worker::{WorkerProgress, WorkerResult};