RatatuiRuby

Terminal UIs,
the Ruby way.

RatatuiRuby is a RubyGem built on Ratatui, a leading TUI library written in Rust. You get native performance with the joy of Ruby.

$ gem install ratatui_ruby

Latest release: v1.3.0

Start small

Rich Moments

Add a spinner, a progress bar, or an inline menu to your CLI script. No full-screen takeover. Your terminal history stays intact.

Inline Viewports

Standard TUIs erase themselves on exit. Your carefully formatted CLI output disappears. Users lose their scrollback.

Inline viewports solve this. They occupy a fixed number of lines, render rich UI, then leave the output in place when done.

Perfect for spinners, menus, progress indicators—any brief moment of richness.

class Spinner
  def main
    RatatuiRuby.run(viewport: :inline, height: 1) do |tui|
      until connected?
        status = tui.paragraph(text: "#{spin} Connecting...")
        tui.draw { |frame| frame.render_widget(status, frame.area) }
        return ending(tui, "Canceled!", :red) if tui.poll_event.ctrl_c?
      end
      ending(tui, "Connected!", :green)
    end
  end

  def ending(tui, message, color) = tui.draw do |frame|
    frame.render_widget(tui.paragraph(text: message, fg: color), frame.area)
  end

  def initialize = (@frame, @finish = 0, Time.now + 2)
  def connected? = Time.now >= @finish # Simulate work
  def spin = SPINNER[(@frame += 1) % SPINNER.length]
  SPINNER = %w[⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏]
end
Spinner.new.main; puts
Go further

Build Something Real

Full-screen applications with keyboard and mouse input. The managed loop sets up the terminal and restores it on exit, even after crashes.

RatatuiRuby.run do |tui|
  loop do
    tui.draw do |frame|
      frame.render_widget(
        tui.paragraph(
          text: "Hello, RatatuiRuby!",
          alignment: :center,
          block: tui.block(
            title: "My App",
            titles: [{ content: "q: Quit", position: :bottom, alignment: :right }],
            borders: [:all],
            border_style: { fg: "cyan" }
          )
        ),
        frame.area
      )
    end

    case tui.poll_event
    in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
      break
    else
      nil
    end
  end
end

The Managed Loop

RatatuiRuby.run enters raw mode, switches to the alternate screen, and restores the terminal on exit.

Inside the block: call draw to render, and poll_event to read input.

Widgets included:

Need something else? Build custom widgets in Ruby!

Ship with confidence

Testing Built In

TUI testing is tedious. You need a headless terminal, event injection, snapshot comparisons, and style assertions. RatatuiRuby bundles all of it.

require "ratatui_ruby/test_helper"

class TestColorPicker < Minitest::Test
  include RatatuiRuby::TestHelper # Built-in mixin

  def test_swatch_widget # Unit testing
    with_test_terminal(10, 3) do
      RatatuiRuby.draw do |frame|
        frame.render_widget(Swatch.new(:red), frame.area)
      end
      assert_cell_style 2, 1, char: "", bg: :red
    end
  end

  def test_input_hex # Integration testing
    with_test_terminal do
      inject_keys "#", "f", "f", "0", "0", "0", "0"
      inject_keys :enter, :q
      ColorPicker.new.run
      assert_snapshots "after_hex_entry"
    end
  end
end

One Include, Everything Works

The module sets up a headless terminal, injects events, and asserts on rendered output. Everything runs in-process with no external dependencies.

What's inside:

Scale up

Full App Solutions

RatatuiRuby renders. For complex applications, add a framework that manages state and composition.

Both use the same widget library, declarative styles, and rendering engine. Both compose cleanly, test easily with snapshots and event injection, and keep state easy to reason about.

Pick the paradigm that fits your brain. You can't choose wrong.

Philosophy

Why RatatuiRuby?

Ruby deserves world-class terminal user interfaces. TUI developers deserve a world-class language.

RatatuiRuby wraps Rust's Ratatui via native extension. The Rust library handles rendering. Your Ruby code handles design.

Text UIs are seeing a renaissance with many new TUI libraries popping up. The Ratatui bindings have proven to be full featured and stable.

Mike Perham, creator of Sidekiq and Faktory

Explore the RatatuiRuby ecosystem →

Why Rust? Why Ruby?

Rust excels at low-level rendering. Ruby excels at expressing domain logic and UI. RatatuiRuby puts each language where it performs best.

Versus CharmRuby

CharmRuby wraps Charm's Go libraries. Both projects give Ruby developers TUI options.

CharmRuby RatatuiRuby
Integration Two runtimes, one process Native extension in Rust
Runtime Go + Ruby (competing) Ruby (Rust has no runtime)
Memory Two uncoordinated GCs One Garbage Collector
Style The Elm Architecture (TEA) TEA, OOP, or Imperative