Quickstart

Welcome to ratatui_ruby! This guide will help you get up and running with your first Terminal User Interface in Ruby.

Installation

See Installation in the README for setup instructions.

Tutorials

Basic Application

Here is a “Hello World” application that demonstrates the core lifecycle of a ratatui_ruby app.

# 1. Initialize the terminal
RatatuiRuby.init_terminal

begin
  # The Main Loop
  loop do
    # 2. Create your UI (Immediate Mode)
    # We define a Paragraph widget inside a Block with a title and borders.
    view = RatatuiRuby::Widgets::Paragraph.new(
      text: "Hello, Ratatui! Press 'q' to quit.",
      alignment: :center,
      block: RatatuiRuby::Widgets::Block.new(
        title: "My Ruby TUI App",
        title_alignment: :center,
        borders: [:all],
        border_style: { fg: "cyan" },
        style: { fg: "white" }
      )
    )

    # 3. Draw the UI
    RatatuiRuby.draw do |frame|
      frame.render_widget(view, frame.area)
    end

    # 4. Poll for events
    case RatatuiRuby.poll_event
    in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
      break
    else
      nil
    end

    # 5. Guard against accidental output (optional but recommended)
    # Wrap any code that might puts/warn to prevent screen corruption.
    RatatuiRuby.guard_io do
      # SomeChattyGem.do_something
    end
  end
ensure
  # 6. Restore the terminal to its original state
  RatatuiRuby.restore_terminal
end

quickstart_lifecycle

How it works

  1. RatatuiRuby.init_terminal: Enters raw mode and switches to the alternate screen.

  2. Immediate Mode UI: On every iteration, describe your UI by creating Data objects (e.g., Paragraph, Block).

  3. RatatuiRuby.draw { |frame| ... }: The block receives a Frame object as a canvas. Render widgets onto specific areas. Nothing is drawn until the block finishes, ensuring flicker-free updates.

  4. RatatuiRuby.poll_event: Returns a typed Event object with predicates like key?, mouse?, resize?, etc. Returns RatatuiRuby::Event::None if no events are pending. Use predicates to check event type without pattern matching.

  5. RatatuiRuby.guard_io { }: Wraps code that might write to stdout/stderr (e.g., chatty gems). Output is swallowed to prevent screen corruption. Optional but recommended for production apps.

  6. RatatuiRuby.restore_terminal: Essential for leaving raw mode and returning to the shell. Always wrap your loop in begin...ensure to guarantee this runs.

Simplified API

You can simplify your code by using RatatuiRuby.run. This method handles the terminal lifecycle for you, yielding a TUI object with factory methods for widgets.

# 1. Initialize the terminal, start the run loop, and ensure the terminal is restored.
RatatuiRuby.run do |tui|
  loop do
    # 2. Create your UI with methods instead of classes.
    view = tui.paragraph(
      text: "Hello, Ratatui! Press 'q' to quit.",
      alignment: :center,
      block: tui.block(
        title: "My Ruby TUI App",
        title_alignment: :center,
        borders: [:all],
        border_style: { fg: "cyan" },
        style: { fg: "white" }
      )
    )

    # 3. Use RatatuiRuby methods, too.
    tui.draw do |frame|
      frame.render_widget(view, frame.area)
    end

    # 4. Poll for events with pattern matching
    case tui.poll_event
    in { type: :key, code: "q" }
      break
    else
      # Ignore other events
    end
  end
end

How it works

  1. RatatuiRuby.run: This context manager initializes the terminal before the block starts and ensures restore_terminal is called when the block exits (even if an error occurs).

  2. Widget Shorthand: The block yields a TUI object (here named tui). This object provides factory methods for every widget, allowing you to write tui.paragraph(...) instead of the more verbose RatatuiRuby::Widgets::Paragraph.new(...).

  3. Method Shorthand: The TUI object also provides aliases for module functions of RatatuiRuby, allowing you to write tui.draw(...) instead of the more verbose RatatuiRuby.draw(...).

  4. Pattern Matching for Events: Use case...in with pattern matching for elegant event dispatch. Always include an else clause at the end to catch unmatched event types (mouse, resize, paste, focus, etc.), otherwise Ruby raises NoMatchingPatternError.

For a deeper dive into the available application architectures (Manual vs Managed), see Application Architecture.

Adding Layouts

Real-world applications often need to split the screen into multiple areas. RatatuiRuby::Layout lets you do this easily.

loop do
  tui.draw do |frame|
    # 1. Split the screen
    top, bottom = tui.layout_split(
      frame.area,
      direction: :vertical,
      constraints: [
        tui.constraint_percentage(75),
        tui.constraint_percentage(25),
      ]
    )

    # 2. Render Top Widget
    frame.render_widget(
      tui.paragraph(
        text: "Hello, Ratatui!",
        alignment: :center,
        block: tui.block(title: "Content", borders: [:all], border_style: { fg: "cyan" })
      ),
      top
    )

    # 3. Render Bottom Widget with Styled Text
    # We use a Line of Spans to style specific characters
    text_line = tui.text_line(
      spans: [
        tui.text_span(content: "Press '"),
        tui.text_span(
          content: "q",
          style: tui.style(modifiers: [:bold, :underlined])
        ),
        tui.text_span(content: "' to quit."),
      ],
      alignment: :center
    )

    frame.render_widget(
      tui.paragraph(
        text: text_line,
        block: tui.block(title: "Controls", borders: [:all])
      ),
      bottom
    )
  end

  case tui.poll_event
  in { type: :key, code: "q" }
    break
  else
    # Ignore other events
  end
end

How it works

  1. tui.layout_split (RatatuiRuby::Layout::Layout.split): Takes an area (like frame.area) and splits it into multiple sub-areas based on constraints.

  2. tui.constraint_* (RatatuiRuby::Layout::Constraint): Defines how space is distributed (e.g., percentage, length, min, max).

  3. Frame#render_widget(widget, rect): You pass the specific area (like top or bottom) to render the widget into that exact region.

  4. tui.text_span (RatatuiRuby::Text::Span): Allows for rich styling within a single line of text.

quickstart_layout

Examples

These examples showcase the full power of ratatui_ruby. You can find their source code in the examples directory.

Widget Demos

Focused examples for individual widgets. Each demonstrates a single widget and its configuration options.

Widget What it demonstrates
Bar Chart Grouped bars, data visualization, custom bar styling
Block Borders, titles, padding, nested widgets
Box Block + Paragraph composition, text wrapping
Calendar Date highlighting, month display, event markers
Chart Line/scatter plots, axes, legends, datasets
Gauge Progress bars, percentage display, unicode blocks
Layout Split Constraint types, flex modes, responsive layouts
Line Gauge Horizontal progress, labels, thin-style gauges
List Selection, scrolling, highlight styles, rich text items
Map Canvas widget, world map rendering, coordinates
Popup Clear widget, modal dialogs, overlay composition
Ratatui Logo Decorative branding widget
Ratatui Mascot ASCII art Ferris mascot
Rect Geometry helpers, area calculations, contains/intersection
Rich Text Spans, lines, inline styling, mixed colors
Scrollbar Orientations, thumb/track styling, scroll state
Scroll Text Paragraph scrolling, viewport control, long content
Sparkline Mini charts, time series, bar sets
Style Colors Named colors, RGB, indexed 256-color palette
Table Row selection, column widths, per-cell styling
Tabs Tab navigation, highlighting, dividers
Text Width Unicode-aware width measurement, CJK support
Canvas Drawing shapes, markers, custom graphics
Cell Buffer cell inspection, styling attributes
Center Centering content, horizontal/vertical alignment
Overlay Layering widgets, modal backgrounds
Custom Render Low-level Draw API, escape hatch for custom widgets

Sample Applications

These larger examples combine widgets into complete applications, demonstrating real-world TUI patterns and architectures.

Application Architecture What you’ll learn
All Events Model-View-Update Event handling, unidirectional data flow, scalable structure
Color Picker Component-Based Hit testing, modal dialogs, encapsulated state
Debugging Showcase Simple Loop Remote debugging, Rust backtraces, improved error messages
Login Form Overlay + Center Modal forms, cursor positioning, text input
Stateful Interaction State Objects ListState/TableState, offset read-back, mouse click-to-row

All Events

all_events

Color Picker

color_picker

Debugging Showcase

debugging_showcase

Login Form

login_form

Next Steps

Now that you’ve seen what ratatui_ruby can do: