Home

Awesome

<div align="center"> <h1><code>iocraft</code></h1> <p> <strong>✨ A Rust crate for beautiful, artisanally crafted CLIs, TUIs, and text-based IO. ✨</strong> </p> <p> <a href="https://github.com/ccbrown/iocraft/actions"><img src="https://img.shields.io/github/actions/workflow/status/ccbrown/iocraft/commit.yaml" alt="GitHub Actions Workflow Status" /></a> <a href="https://docs.rs/iocraft/"><img src="https://img.shields.io/docsrs/iocraft" alt="docs.rs" /></a> <a href="https://crates.io/crates/iocraft"><img src="https://img.shields.io/crates/v/iocraft" alt="crates.io" /></a> <a href="https://app.codecov.io/github/ccbrown/iocraft"><img src="https://img.shields.io/codecov/c/github/ccbrown/iocraft" alt="Codecov" /></a> </p> </div>

iocraft is a library for crafting beautiful text output and interfaces for the terminal or logs. It allows you to easily build complex layouts and interactive elements using a declarative API.

Features

Getting Started

If you're familiar with React, you'll feel right at home with iocraft. It uses all the same concepts, but is text-focused and made for Rust.

Here's your first iocraft program:

use iocraft::prelude::*;

fn main() {
    element! {
        Box(
            border_style: BorderStyle::Round,
            border_color: Color::Blue,
        ) {
            Text(content: "Hello, world!")
        }
    }
    .print();
}
<img src="https://raw.githubusercontent.com/ccbrown/iocraft/refs/heads/main/examples/images/hello-world.png" height=237 />

Your UI is composed primarily via the element! macro, which allows you to declare your UI elements in a React/SwiftUI-like syntax.

iocraft provides a few built-in components, such as Box, Text, and TextInput, but you can also create your own using the #[component] macro.

For example, here's a custom component that uses a hook to display a counter which increments every 100ms:

use iocraft::prelude::*;
use std::time::Duration;

#[component]
fn Counter(mut hooks: Hooks) -> impl Into<AnyElement<'static>> {
    let mut count = hooks.use_state(|| 0);

    hooks.use_future(async move {
        loop {
            smol::Timer::after(Duration::from_millis(100)).await;
            count += 1;
        }
    });

    element! {
        Text(color: Color::Blue, content: format!("counter: {}", count))
    }
}

fn main() {
    smol::block_on(element!(Counter).render_loop()).unwrap();
}
<img src="https://raw.githubusercontent.com/ccbrown/iocraft/refs/heads/main/examples/images/counter.svg" />

More Examples

There are many examples on GitHub which demonstrate various concepts such as tables, progress bars, fullscreen apps, forms, and more!

<img src="https://raw.githubusercontent.com/ccbrown/iocraft/refs/heads/main/examples/images/table.png" height=402 /> <img src="https://raw.githubusercontent.com/ccbrown/iocraft/refs/heads/main/examples/images/form.png" height=387 /> <img src="https://raw.githubusercontent.com/ccbrown/iocraft/refs/heads/main/examples/images/overlap.png" height=450 /> <img src="https://raw.githubusercontent.com/ccbrown/iocraft/refs/heads/main/examples/images/calculator.png" height=450 /> <img src="https://raw.githubusercontent.com/ccbrown/iocraft/refs/heads/main/examples/images/weather-powershell.png" height=350 />

Shoutouts

iocraft was inspired by Dioxus and Ink, which you should also check out, especially if you're building graphical interfaces or interested in using JavaScript/TypeScript.

You may also want to check out Ratatui, which serves a similar purpose with a less declarative API.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.