Quick lookup for every built-in widget and helper. One example per struct, key fields inline. For concepts see Building UIs; for full option shapes, the module docs.

Styles & rich text

Style

%Style{
  fg: :green,                         # or {r,g,b}, or 0..255 index
  bg: :reset,
  modifiers: [:bold, :italic, :underlined, :reversed, :dim]
}

Colors accept :reset, named atoms, {r, g, b}, or 0–255. Modifiers are additive.

Rich text spans/lines

alias ExRatatui.Text.{Line, Span}

Line.new([
  Span.new(" ok ", style: %Style{fg: :green, modifiers: [:bold]}),
  Span.new(" build passed", style: %Style{fg: :gray})
])

Accepted by Paragraph.text, List.items, Table.rows/header, Tabs.titles, Block.title.

Layout

Layout.split/3

alias ExRatatui.Layout

[left, right] =
  Layout.split(frame_rect, :horizontal, [
    {:percentage, 30},
    {:percentage, 70}
  ])

Direction: :horizontal or :vertical. Constraints: :length, :percentage, :min, :max, :ratio.

%Rect{}

%ExRatatui.Layout.Rect{x: 0, y: 0, width: 80, height: 24}

All widgets render into a Rect. Returned from Layout.split/3, derived from %Frame{}, or built manually for absolute placement.

Text & content

Paragraph

%Paragraph{
  text: "Hello!",                      # String | Span | Line | [Span]
  style: %Style{fg: :green},
  alignment: :center,                  # :left | :center | :right
  wrap: true,
  scroll: {0, 0},                      # {vertical, horizontal}
  block: %Block{title: " Info ", borders: [:all]}
}

Markdown

%Markdown{
  content: "# Title\n\n**bold** *italic* `code`\n\n- a\n- b",
  wrap: true,
  scroll: {0, 0},
  block: %Block{borders: [:all]}
}

Supports headings, bold/italic, inline code, lists.

Lists, tables & scrolling

List

%List{
  items: ["Item 1", "Item 2", "Item 3"],
  selected: 0,
  highlight_style: %Style{fg: :yellow, modifiers: [:bold]},
  highlight_symbol: ">> ",
  block: %Block{title: " Menu ", borders: [:all]}
}

Table

%Table{
  header: ["Name", "Score"],
  rows: [["Alice", "95"], ["Bob", "87"]],
  widths: [{:percentage, 70}, {:percentage, 30}],
  selected: 0,
  highlight_style: %Style{fg: :yellow},
  column_spacing: 1,
  block: %Block{borders: [:all]}
}

WidgetList

%WidgetList{
  items: [
    {%Paragraph{text: "Row 1"}, 3},    # {widget, height}
    {%Paragraph{text: "Row 2"}, 5}
  ],
  selected: 0,
  scroll_offset: 0,
  highlight_style: %Style{bg: {50, 50, 50}}
}

Row-clipped scroll. Good for 1k+ items; only visible rows cross the NIF boundary.

Scrollbar

%Scrollbar{
  orientation: :vertical_right,        # or :vertical_left, :horizontal_bottom, :horizontal_top
  content_length: 100,
  position: 25,
  viewport_content_length: 20,
  thumb_style: %Style{fg: :yellow}
}

Progress & activity

Gauge

%Gauge{
  ratio: 0.65,                         # 0.0..1.0
  label: "65%",
  gauge_style: %Style{fg: :green},
  block: %Block{borders: [:all]}
}

LineGauge

%LineGauge{
  ratio: 0.4,
  label: "Loading...",
  filled_style: %Style{fg: :blue},
  unfilled_style: %Style{fg: :dark_gray}
}

Single-cell-tall bar — great for compact status rows.

Sparkline

%Sparkline{
  data: [0, 1, 3, 5, 8, nil, 2, 4],    # nil = absent
  max: 8,                              # nil auto-scales
  direction: :left_to_right,
  bar_set: :nine_levels,
  style: %Style{fg: :cyan}
}

Throbber

%Throbber{
  label: "Loading",
  throbber_set: :braille,              # :braille | :dots | :line | :ascii
  step: state.tick,                    # caller increments
  throbber_style: %Style{fg: :cyan}
}

Drive with Subscription.interval/3 (reducer) or Process.send_after/3 (callback).

BarChart

alias ExRatatui.Widgets.Bar

%BarChart{
  data: [
    %Bar{label: "Mon", value: 42},
    %Bar{label: "Tue", value: 67, style: %Style{fg: :yellow}}
  ],
  bar_width: 5,
  bar_gap: 1,
  direction: :vertical,                # or :horizontal
  max: 100                             # nil auto-scales
}

Use :groups with %BarGroup{} for side-by-side clusters (mutually exclusive with :data).

Input

TextInput

state = ExRatatui.text_input_new()     # mount once, keep in app state

%TextInput{
  state: state,
  placeholder: "Type here...",
  style: %Style{fg: :white},
  cursor_style: %Style{bg: :white, fg: :black},
  block: %Block{borders: [:all]}
}

ExRatatui.text_input_handle_key(state, key_event)
value = ExRatatui.text_input_get_value(state)

Textarea

state = ExRatatui.textarea_new()

%Textarea{
  state: state,
  placeholder: "Enter message...",
  cursor_line_style: %Style{bg: {40, 40, 40}},
  line_number_style: %Style{fg: :dark_gray},  # nil hides line numbers
  block: %Block{borders: [:all]}
}

ExRatatui.textarea_handle_key(state, key_event)
value = ExRatatui.textarea_get_value(state)

Enter = newline, Ctrl+Enter = submit.

Checkbox

%Checkbox{
  label: "Enable notifications",
  checked: true,
  checked_style: %Style{fg: :green},
  checked_symbol: "[x]",
  unchecked_symbol: "[ ]"
}

SlashCommands

alias ExRatatui.Widgets.SlashCommands
alias ExRatatui.Widgets.SlashCommands.Command

commands = [
  %Command{name: "help", description: "Show help", aliases: ["h", "?"]},
  %Command{name: "quit", description: "Exit", aliases: ["q"]}
]

case SlashCommands.parse(input_text) do
  {:slash, query} -> SlashCommands.match_commands(commands, query)
  :no_slash -> []
end

Pair the matches with a %Popup{} in render/2 to show autocomplete.

Charts & canvas

Chart

alias ExRatatui.Widgets.Chart.{Axis, Dataset}

%Chart{
  datasets: [
    %Dataset{
      name: "CPU",
      data: [{0.0, 12.0}, {1.0, 25.0}, {2.0, 48.0}],
      marker: :braille,
      graph_type: :line,                # :line | :scatter | :bar
      style: %Style{fg: :cyan}
    }
  ],
  x_axis: %Axis{title: "Time", bounds: {0.0, 3.0}, labels: ["0", "1", "2", "3"]},
  y_axis: %Axis{title: "Usage %", bounds: {0.0, 100.0}, labels: ["0", "50", "100"]},
  legend_position: :top_right            # nil hides
}

Canvas

alias ExRatatui.Widgets.Canvas.{Circle, Label, Line, Points, Rectangle}

%Canvas{
  x_bounds: {0.0, 100.0},
  y_bounds: {0.0, 50.0},
  marker: :braille,                     # :braille | :dot | :block | :bar | :half_block
  background_color: :black,
  shapes: [
    %Line{x1: 0.0, y1: 0.0, x2: 100.0, y2: 50.0, color: :cyan},
    %Rectangle{x: 10.0, y: 10.0, width: 30.0, height: 20.0, color: :yellow},
    %Circle{x: 70.0, y: 25.0, radius: 10.0, color: :magenta},
    %Points{coords: [{20.0, 40.0}, {50.0, 30.0}], color: :green},
    %Label{x: 70.0, y: 25.0, text: "★", color: :white}
  ]
}

World map

alias ExRatatui.Widgets.Canvas.Map, as: CanvasMap

%Canvas{
  x_bounds: {-180.0, 180.0},
  y_bounds: {-90.0, 90.0},
  marker: :dot,
  shapes: [
    %CanvasMap{resolution: :high, color: :green},
    %Label{x: -74.0, y: 40.7, text: "NYC", color: :yellow}
  ]
}

Containers & overlays

Block

%Block{
  title: " Panel ",                     # String | Span | Line | [Span]
  borders: [:all],                      # or [:top, :left, ...]
  border_type: :rounded,                # :plain | :rounded | :double | :thick
  border_style: %Style{fg: :cyan},
  padding: {0, 0, 0, 0}                 # {left, right, top, bottom}
}

Wraps another widget via that widget's :block field.

%Popup{
  content: %Paragraph{text: "Are you sure?"},
  percent_width: 50,                    # or fixed_width: 40
  percent_height: 30,                   # or fixed_height: 10
  block: %Block{title: " Confirm ", borders: [:all], border_type: :double}
}

Renders centered on top of whatever's already drawn.

Tabs

%Tabs{
  titles: ["Overview", "Details", "Settings"],
  selected: 0,
  highlight_style: %Style{fg: :yellow, modifiers: [:bold]},
  divider: " | ",
  padding: {1, 1},
  block: %Block{borders: [:bottom]}
}

Clear

%Clear{}

Fills the rect with blank cells. Use before a popup to dim underlying content.

Calendar

%Calendar{
  display_date: ~D[2026-03-15],
  events: [
    {~D[2026-03-10], %Style{fg: :red, modifiers: [:bold]}},
    {~D[2026-03-20], %Style{fg: :green}}
  ],
  default_style: %Style{fg: :white},
  show_month_header: true,
  header_style: %Style{fg: :yellow, modifiers: [:bold]},
  show_weekdays_header: true,
  weekday_style: %Style{fg: :cyan},
  show_surrounding: %Style{fg: :dark_gray},   # nil hides surrounding days
  block: %Block{title: " March ", borders: [:all]}
}

Needs ~22×8 cells (24×10 with a block). events accepts a keyword-like list of {%Date{}, %Style{}} tuples or a %{Date => Style} map.