Expand description
§Teapot
A Rust-native terminal UI framework following the Elm Architecture, inspired by the Charm.sh ecosystem (Bubble Tea, Bubbles, Huh).
§Architecture
This framework implements the Model-Update-View pattern:
- Model: Your application state
- Update: Handle messages and update state
- View: Render state as a string
§Quick Start
use teapot::{Model, Program, Cmd, KeyCode, Event};
struct Counter {
count: i32,
}
enum Msg {
Increment,
Decrement,
Quit,
}
impl Model for Counter {
type Message = Msg;
fn init(&self) -> Option<Cmd<Self::Message>> {
None
}
fn update(&mut self, msg: Self::Message) -> Option<Cmd<Self::Message>> {
match msg {
Msg::Increment => self.count += 1,
Msg::Decrement => self.count -= 1,
Msg::Quit => return Some(Cmd::quit()),
}
None
}
fn view(&self) -> String {
format!("Count: {}\n\nPress +/- to change, q to quit", self.count)
}
fn handle_event(&self, event: Event) -> Option<Self::Message> {
match event {
Event::Key(key) => match key.code {
KeyCode::Char('+') | KeyCode::Char('=') => Some(Msg::Increment),
KeyCode::Char('-') => Some(Msg::Decrement),
KeyCode::Char('q') | KeyCode::Esc => Some(Msg::Quit),
_ => None,
},
_ => None,
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let counter = Counter { count: 0 };
Program::new(counter).run()?;
Ok(())
}§Components
The components module provides reusable UI widgets:
Spinner- Animated loading indicatorsProgress- Progress barsTextInput- Single-line text inputTextArea- Multi-line text inputSelect- Single option selectionMultiSelect- Multiple option selectionConfirm- Yes/No confirmationList- Filterable, paginated listTable- Scrollable data tableMultiProgress- Multiple parallel progress bars
§Forms
The forms module provides declarative form building:
ⓘ
use teapot::forms::{Form, Group, Input, Select, Confirm};
let form = Form::new()
.group(
Group::new()
.field(Input::new("name").title("Your name"))
.field(Select::new("color").title("Favorite color")
.options(["Red", "Green", "Blue"]))
)
.group(
Group::new()
.field(Confirm::new("agree").title("Do you agree?"))
);§CI/Script Compatibility
The framework automatically detects non-interactive environments and adjusts behavior accordingly (no animations, no prompts, clear errors).
§Accessible Mode
For screen reader users and other accessible environments, set the
ACCESSIBLE=1 environment variable. This enables:
- Plain text prompts without ANSI formatting
- Numbered options for selection components
- Line-based input instead of raw terminal mode
Forms can be run in accessible mode:
ⓘ
let mut form = Form::new()
.group(Group::new()
.field(InputField::new("name").title("Your Name").build()));
if let Some(results) = form.run_accessible()? {
println!("Name: {}", results.get_string("name").unwrap_or(""));
}Components implement the Accessible trait for custom accessible handling.
Re-exports§
pub use components::BadgeVariant;pub use components::Column;pub use components::Confirm;pub use components::FilePicker;pub use components::List;pub use components::MultiProgress;pub use components::MultiSelect;pub use components::Progress;pub use components::Select;pub use components::Spinner;pub use components::StatusBadge;pub use components::Tab;pub use components::TabBar;pub use components::Table;pub use components::TaskList;pub use components::TaskProgressView;pub use components::TaskStep;pub use components::TextArea;pub use components::TextInput;pub use components::TitleBar;pub use forms::Form;pub use forms::Group;pub use runtime::cmd;pub use runtime::Accessible;pub use runtime::AccessibleInput;pub use runtime::Cmd;pub use runtime::Model;pub use runtime::Program;pub use runtime::ProgramOptions;pub use runtime::Sub;pub use style::BLINK;pub use style::BOLD;pub use style::CLEAR_LINE;pub use style::CR;pub use style::CURSOR_UP;pub use style::DIM;pub use style::HIDDEN;pub use style::ITALIC;pub use style::RESET;pub use style::REVERSE;pub use style::STRIKETHROUGH;pub use style::UNDERLINE;pub use style::Border;pub use style::Color;pub use style::Style;pub use terminal::Event;pub use terminal::KeyCode;pub use terminal::KeyEvent;pub use terminal::KeyModifiers;pub use terminal::MouseEvent;pub use util::ManagedWorker;pub use util::ScrollState;pub use util::WorkerHandle;