RubyGems Navigation menu

ratatui_ruby 1.0.0.pre.beta.2

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 --pre

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.

require "ratatui_ruby"

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) }
  end
end

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),
        frame.area
      )
    end

    case tui.poll_event
    in { type: :key, code: "q" } then break
    else nil
    end
  end
end

Widgets included:

Layout

Block, Center, Clear (Popup, Modal), Layout (Split, Grid), Overlay

Data

Bar Chart, Chart, Gauge, Line Gauge, Sparkline, Table

Text

Cell, List, Rich Text (Line, Span), Scrollbar (Scroll), Tabs

Graphics

Calendar, Canvas, Map (World Map)

Need something else? Build custom widgets in Ruby!


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

  def test_swatch_widget
    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
end

What’s inside:

  • Headless terminal — No real TTY needed

  • Snapshots — Plain text and rich (ANSI colors)

  • Event injection — Keys, mouse, paste, resize

  • Style assertions — Color, bold, underline at any cell

  • Test doubles — Mock frames and stub rects

  • UPDATE_SNAPSHOTS=1 — Regenerate baselines in one command


Inline Menu Example

require "ratatui_ruby"

# This example renders an inline menu. Arrow keys select, enter confirms.
# The menu appears in-place, preserving scrollback. When the user chooses,
# the TUI closes and the script continues with the selected value.
class RadioMenu
  CHOICES = ["Production", "Staging", "Development"]         # ASCII strings are universally supported.
  PREFIXES = { active: "●", inactive: "○" }                  # Some terminals may not support Unicode.
  CONTROLS = "↑/↓: Select | Enter: Choose | Ctrl+C: Cancel"  # Let users know what keys you handle.
  TITLES = ["Select Environment",                            # The default title position is top left.
            { content: CONTROLS,                             # Multiple titles can save space.
              position: :bottom,                             # Titles go on the top or bottom,
              alignment: :right }]                           # aligned left, right, or center

  def call                                                   # This method blocks until a choice is made.
    RatatuiRuby.run(viewport: :inline, height: 5) do |tui|   # RatauiRuby.run manages the terminal.
      @tui = tui                                             # The TUI instance is safe to store.
      show_menu until chosen?                                # You can use any loop keyword you like.
    end                                                      # `run` won't return until your block does,
    RadioMenu::CHOICES[@choice]                              # so you can use it synchronously.
  end
                                                             # Classes like RadioMenu are convenient for
  private                                                    # CLI authors to offer "rich moments."

  def show_menu = @tui.draw do |frame|                       # RatatuiRuby gives you low-level access.
    widget = @tui.paragraph(                                 # But the TUI facade makes it easy to use.
      text: menu_items,                                      # Text can be spans, lines, or paragraphs.
      block: @tui.block(borders: :all, titles: TITLES)       # Blocks give you boxes and titles, and hold
    )                                                        # one or more widgets. We only use one here,
    frame.render_widget(widget, frame.area)                  # but "area" lets you compose sub-views.
  end

  def chosen?                                                # You are responsible for handling input.
    interaction = @tui.poll_event                            # Every frame, you receive an event object:
    return choose if interaction.enter?                      # Key, Mouse, Resize, Paste, FocusGained,
                                                             # FocusLost, or None objects. They come with
    move_by(-1) if interaction.up?                           # predicates, support pattern matching, and
    move_by(1) if interaction.down?                          # can be inspected for properties directly.
    quit! if interaction.ctrl_c?                             # Your application must handle every input,
    false                                                    # even interrupts and other exit patterns.
  end

  def choose                                                 # Here, the loop is about to exit, and the
    prepare_next_line                                        # block will return. The inline viewport
    @choice                                                  # will be torn down and the terminal will
  end                                                        # be restored, but you are responsible for
                                                             # positioning the cursor.
  def prepare_next_line                                      # To ensure the next output is on a new
    area = @tui.viewport_area                                # line, query the viewport area and move
    RatatuiRuby.cursor_position = [0, area.y + area.height]  # the cursor to the start of the last line.
    puts                                                     # Then print a newline.
  end

  def quit!                                                  # All of your familiar Ruby control flow
    prepare_next_line                                        # keywords work as expected, so we can
    exit 0                                                   # use them to leave the TUI.
  end

  def move_by(line_count)                                    # You are in full control of your UX, so
    @choice = (@choice + line_count) % CHOICES.size          # you can implement any logic you need:
  end                                                        # Would you "wrap around" here, or not?
                                                             #
  def menu_items = CHOICES.map.with_index do |choice, i|     # Notably, RatatuiRuby has no concept of
    "\#{prefix_for(i)} \#{choice}"                             # "menus" or "radio buttons". You are in
  end                                                        # full control, but it also means you must
  def prefix_for(choice_index)                               # implement the logic yourself. For larger
    return PREFIXES[:active] if choice_index == @choice      # applications, consider using Rooibos,
    PREFIXES[:inactive]                                      # an MVU framework built with RatatuiRuby.
  end                                                        # Or, use the upcoming ratatui-ruby-kit,
                                                             # our object-oriented component library.
  def initialize = @choice = 0                               # However, those are both optional, and
end                                                          # designed for full-screen Terminal UIs.
                                                             # RatatuiRuby will always give you the most
choice = RadioMenu.new.call                                  # control, and is enough for "rich CLI
puts "You chose \#{choice}!"                                  # moments" like this one.

Full App Solutions

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

Rooibos (Framework)

Model-View-Update architecture. Inspired by Elm, Bubble Tea, and React + Redux. Your UI is a pure function of state.

  • Functional programming with MVU

  • Commands work off the main thread

  • Messages, not callbacks, drive updates

Kit (Coming Soon)

Component-based architecture. Encapsulate state, input handling, and rendering in reusable pieces.

  • OOP with stateful components

  • Separate UI state from domain logic

  • Built-in focus management & click handling

Both use the same widget library and rendering engine. Pick the paradigm that fits your brain.


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

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.

Integration

CharmRuby: Two runtimes, one process. RatatuiRuby: Native extension in Rust.

Runtime

CharmRuby: Go + Ruby (competing). RatatuiRuby: Ruby (Rust has no runtime).

Memory

CharmRuby: Two uncoordinated GCs. RatatuiRuby: One Garbage Collector.

Style

CharmRuby: The Elm Architecture (TEA). RatatuiRuby: TEA, OOP, or Imperative.


Links

Get Started

Quickstart, Examples, API Reference, Guides

Ecosystem

Rooibos, Kit (Planned), Framework (Planned), UI Widgets (Planned)

Community

Discuss and Chat, Announcements, Development, Bug Tracker

Contribute

Contributing Guide, Code of Conduct, Project History, Pull Requests


Website

www.ratatui-ruby.dev

Source

git.sr.ht/~kerrick/ratatui_ruby

RubyGems

rubygems.org/gems/ratatui_ruby

Upstream

ratatui.rs

Build Status

builds.sr.ht/~kerrick/ratatui_ruby

© 2026 Kerrick Long · Library: LGPL-3.0-or-later · Website: CC-BY-NC-ND-4.0 · Snippets: MIT-0

Gemfile:
=

安裝:
=

版本列表:

  1. 1.0.0.pre.beta.2 January 21, 2026 (17.0 MB)
  2. 1.0.0.pre.beta.1 January 21, 2026 (17.0 MB)
  3. 0.10.3 January 17, 2026 (17.0 MB)
  4. 0.10.2 January 15, 2026 (17.0 MB)
  5. 0.10.1 January 11, 2026 (16.3 MB)
顯示所有版本(共 21)

Runtime 相依性套件 (2):

rb_sys ~> 0.9
rexml ~> 3.4

Development 相依性套件 (4):

debug >= 1.0
faker ~> 3.5.3
rake-compiler ~> 1.2
rdoc ~> 7.0

擁有者:

推送者:

作者:

  • Kerrick Long

SHA 256 總和檢查碼:

=

總下載次數 5,524

這個版本 49

版本发布:

授權:

LGPL-3.0-or-later

Ruby 版本需求: >= 3.2.9, < 5

相關連結: