Demonstrates the Block widget with interactive attribute cycling.
Blocks are the foundation of terminal layouts, providing structure, borders, and titles. This demo showcases all available parameters, including advanced title positioning, directional padding, and custom border sets.
Examples
Run the demo from the terminal:
ruby examples/widget_block/app.rb

Source Code
# frozen_string_literal: true #-- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com> # SPDX-License-Identifier: MIT-0 #++ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__) require "ratatui_ruby" # Demonstrates the Block widget with interactive attribute cycling. # # Blocks are the foundation of terminal layouts, providing structure, borders, and titles. # This demo showcases all available parameters, including advanced title positioning, # directional padding, and custom border sets. # # === Examples # # Run the demo from the terminal: # # ruby examples/widget_block/app.rb # # rdoc-image:/doc/images/widget_block.png class WidgetBlock def initialize @title_configs = [ { name: "None", title: nil }, { name: "Main Title", title: "Main Title" }, ] @title_index = 1 @titles_configs = [ { name: "None", titles: [] }, { name: "Top + Bottom", titles: [ { content: "Top Right", alignment: :right, position: :top }, { content: "Bottom Left", alignment: :left, position: :bottom }, ], }, { name: "Complex", titles: [ { content: "★ Left ★", alignment: :left, position: :top }, { content: "Center", alignment: :center, position: :top }, { content: "Right", alignment: :right, position: :top }, { content: "Bottom Center", alignment: :center, position: :bottom }, ], }, ] @titles_index = 1 @alignment_configs = [ { name: "Left", alignment: :left }, { name: "Center", alignment: :center }, { name: "Right", alignment: :right }, ] @alignment_index = 1 # Center @border_configs = [ { name: "All", borders: [:all] }, { name: "Top/Bottom", borders: [:top, :bottom] }, { name: "Left/Right", borders: [:left, :right] }, { name: "None", borders: [] }, ] @border_index = 0 @border_type_configs = [ { name: "Rounded", type: :rounded }, { name: "Plain", type: :plain }, { name: "Double", type: :double }, { name: "Thick", type: :thick }, { name: "Quadrant Inside", type: :quadrant_inside }, { name: "Quadrant Outside", type: :quadrant_outside }, { name: "Custom Set", type: nil, set: { top_left: "1", top_right: "2", bottom_left: "3", bottom_right: "4", vertical_left: "5", vertical_right: "6", horizontal_top: "7", horizontal_bottom: "8", }, }, ] @border_type_index = 0 @padding_configs = [ { name: "Uniform (2)", padding: 2 }, { name: "None (0)", padding: 0 }, { name: "Directional (L:4, T:2)", padding: [4, 0, 2, 0] }, { name: "Narrow (H:1, V:0)", padding: [1, 1, 0, 0] }, ] @padding_index = 0 end def run RatatuiRuby.run do |tui| @tui = tui @title_styles = [ { name: "None", style: nil }, { name: "Magenta Bold", style: @tui.style(fg: :magenta, modifiers: [:bold]) }, { name: "Cyan Bold", style: @tui.style(fg: :cyan, modifiers: [:bold]) }, { name: "Yellow Italic", style: @tui.style(fg: :yellow, modifiers: [:italic]) }, ] @title_style_index = 1 # Magenta Bold @border_styles = [ { name: "Cyan", style: @tui.style(fg: :cyan) }, { name: "Magenta Bold", style: @tui.style(fg: :magenta, modifiers: [:bold]) }, { name: "None", style: nil }, { name: "Blue on White", style: @tui.style(fg: :blue, bg: :white) }, ] @border_style_index = 0 @base_styles = [ { name: "Dark Gray", style: @tui.style(fg: :dark_gray) }, { name: "None", style: nil }, { name: "White on Black", style: @tui.style(fg: :white, bg: :black) }, ] @base_style_index = 1 @hotkey_style = @tui.style(modifiers: [:bold, :underlined]) loop do render break if handle_input == :quit sleep 0.05 end end end private def render title_config = @title_configs[@title_index] titles_config = @titles_configs[@titles_index] alignment_config = @alignment_configs[@alignment_index] title_style_config = @title_styles[@title_style_index] border_config = @border_configs[@border_index] border_type_config = @border_type_configs[@border_type_index] border_style_config = @border_styles[@border_style_index] base_style_config = @base_styles[@base_style_index] padding_config = @padding_configs[@padding_index] @tui.draw do |frame| main_area, control_area = @tui.layout_split( frame.area, direction: :vertical, constraints: [ @tui.constraint_fill(1), @tui.constraint_length(10), ] ) # Render the demo block demo_block = @tui.block( title: title_config[:title], titles: titles_config[:titles], title_alignment: alignment_config[:alignment], title_style: title_style_config[:style], borders: border_config[:borders], border_type: border_type_config[:type], border_set: border_type_config[:set], border_style: border_style_config[:style], style: base_style_config[:style], padding: padding_config[:padding] ) # Paragraph inside the block to show padding/content interaction content = @tui.paragraph( text: "This paragraph is rendered inside the Block widget.\n" \ "You can see how padding and base style affect this content.\n\n" \ "Current State:\n" \ "• Padding: #{padding_config[:name]}\n" \ "• Borders: #{border_config[:name]}\n" \ "• Type: #{border_type_config[:name]}", block: demo_block ) frame.render_widget(content, main_area) # Render control panel control_panel = @tui.block( title: "Controls", borders: [:all], children: [ @tui.paragraph( text: [ @tui.text_line(spans: [ @tui.text_span(content: "t", style: @hotkey_style), @tui.text_span(content: ": Title (#{title_config[:name]}) "), @tui.text_span(content: "a", style: @hotkey_style), @tui.text_span(content: ": Alignment (#{alignment_config[:name]}) "), @tui.text_span(content: "s", style: @hotkey_style), @tui.text_span(content: ": Title Style (#{title_style_config[:name]})"), ]), @tui.text_line(spans: [ @tui.text_span(content: "e", style: @hotkey_style), @tui.text_span(content: ": Additional Titles (#{titles_config[:name]})"), ]), @tui.text_line(spans: [ @tui.text_span(content: "b", style: @hotkey_style), @tui.text_span(content: ": Borders (#{border_config[:name]}) "), @tui.text_span(content: "y", style: @hotkey_style), @tui.text_span(content: ": Border Type (#{border_type_config[:name]})"), ]), @tui.text_line(spans: [ @tui.text_span(content: "c", style: @hotkey_style), @tui.text_span(content: ": Border Style (#{border_style_config[:name]}) "), @tui.text_span(content: "p", style: @hotkey_style), @tui.text_span(content: ": Padding (#{padding_config[:name]})"), ]), @tui.text_line(spans: [ @tui.text_span(content: "f", style: @hotkey_style), @tui.text_span(content: ": Base Style (#{base_style_config[:name]}) "), @tui.text_span(content: "q", style: @hotkey_style), @tui.text_span(content: ": Quit"), ]), ] ), ] ) frame.render_widget(control_panel, control_area) end end private def handle_input case @tui.poll_event in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] } :quit in type: :key, code: "t" @title_index = (@title_index + 1) % @title_configs.size in type: :key, code: "e" @titles_index = (@titles_index + 1) % @titles_configs.size in type: :key, code: "a" @alignment_index = (@alignment_index + 1) % @alignment_configs.size in type: :key, code: "s" @title_style_index = (@title_style_index + 1) % @title_styles.size in type: :key, code: "b" @border_index = (@border_index + 1) % @border_configs.size in type: :key, code: "y" @border_type_index = (@border_type_index + 1) % @border_type_configs.size in type: :key, code: "c" @border_style_index = (@border_style_index + 1) % @border_styles.size in type: :key, code: "p" @padding_index = (@padding_index + 1) % @padding_configs.size in type: :key, code: "f" @base_style_index = (@base_style_index + 1) % @base_styles.size else nil end end end WidgetBlock.new.run if __FILE__ == $PROGRAM_NAME