Component Gallery
View SourceAll Components are available via the View DSL after use Raxol.Core.Runtime.Application. Layout containers (column, row, box) use do block syntax. Everything else is a plain function call.
To see them all running: mix raxol.playground (interactive demos across all categories).
Layout
Layout Components arrange children on screen. These are the skeleton of every Raxol UI.
column
Vertical stack. Children are arranged top-to-bottom.
column style: %{gap: 1, padding: 1, align_items: :center} do
[
text("Header", style: [:bold]),
divider(),
text("Body content"),
spacer(),
text("Footer", style: [:dim])
]
endStyle options: gap, padding, align_items (:start, :center, :end, :stretch), flex, width, height.
row
Horizontal stack. Children are arranged left-to-right.
row style: %{gap: 2, align_items: :center} do
[
text("Status:"),
text("Online", style: %{fg: :green, bold: true}),
spacer(),
button("Refresh", on_click: :refresh)
]
endSame style options as column. Use spacer() to push items apart.
box
Container with optional border and padding. Good for grouping related content.
box style: %{border: :single, padding: 1, width: 40} do
column style: %{gap: 1} do
[
text("User Profile", style: [:bold]),
text("Name: #{model.name}"),
text("Email: #{model.email}")
]
end
endBorder styles: :none, :single, :double, :rounded, :bold, :dashed.
spacer
Flexible space that fills available room. Useful for pushing items to opposite ends of a row or column.
row do
[text("Left"), spacer(), text("Right")]
endOptions: size (integer, default 1), direction (:vertical or :horizontal).
divider
Horizontal line separator.
column do
[text("Section A"), divider(), text("Section B")]
endOptions: char (string, default "-"), style.
split_pane
Resizable split layout with two panes.
split_pane(
direction: :horizontal,
ratio: {1, 2},
min_size: 10,
children: [left_panel, right_panel]
)Options: direction (:horizontal or :vertical), ratio (tuple, default {1, 1}), min_size (integer, default 5).
Text & Display
Components for showing information to the user. These are all display-only, with no user interaction.
text
Styled text content. The most basic Component.
# Style atoms
text("Bold text", style: [:bold])
text("Dimmed", style: [:dim])
text("Warning", style: [:bold, :underline])
# Color via style map
text("Error", style: %{fg: :red, bold: true})
text("Success", style: %{fg: :green, bg: :black})
# fg/bg also work as keyword opts
text("Custom", fg: :cyan, bg: :blue)Style atoms: :bold, :dim, :italic, :underline, :strikethrough, :reverse.
Colors: :black, :red, :green, :yellow, :blue, :magenta, :cyan, :white, plus RGB tuples {r, g, b} and hex strings "#ff6600". Auto-downsampled to whatever the terminal supports.
label
Alias for text with an explicit content key.
label(content: "Field name:", style: %{bold: true})progress
Progress bar indicator.
progress(value: 65, max: 100)The underlying component module (Raxol.UI.Components.Display.Progress) supports more options when used directly: show_percentage, label, animated, width.
list
Render a list of items, with optional selection highlighting.
list(items: ["Elixir", "Rust", "Go", "Zig"])
list(items: model.todos, selected: model.selected_index)table
Tabular data display with headers.
table(
headers: ["Name", "Role", "Status"],
rows: [
["Alice", "Admin", "Active"],
["Bob", "User", "Idle"],
["Carol", "User", "Active"]
]
)The component module (Raxol.UI.Components.Table) supports much more when used directly: column_widths (:auto or explicit list), border_style, sortable, filterable, selectable, striped, alignments. Handles keyboard navigation for row selection.
tree
Hierarchical tree view with expand/collapse. Component module only (not available as a View DSL function).
alias Raxol.UI.Components.Display.Tree
nodes = [
%{id: "src", label: "src/", children: [
%{id: "lib", label: "lib/", children: [
%{id: "app", label: "app.ex", children: []}
]},
%{id: "test", label: "test/", children: []}
]}
]
# In init/1:
{:ok, tree_state} = Tree.init(%{id: "file_tree", nodes: nodes})
# In view/1 (render the tree state):
Tree.render(model.tree_state, context)Keyboard: Up/Down (navigate), Right (expand), Left (collapse/go to parent), Enter/Space (select), Home/End (jump).
Options: indent_size, on_select, on_expand, on_collapse.
viewport
Scrollable container for content larger than the visible area. Component module only.
alias Raxol.UI.Components.Display.Viewport
{:ok, vp} = Viewport.init(%{
id: "log_view",
children: log_lines,
visible_height: 20,
show_scrollbar: true
})
# Scroll programmatically:
vp = Viewport.update({:scroll_by, 5}, vp)
vp = Viewport.update({:scroll_to, 0}, vp)status_bar
Fixed status bar for key-value display. Component module only.
alias Raxol.UI.Components.Display.StatusBar
{:ok, bar} = StatusBar.init(%{
id: "status",
items: [
%{key: "branch", label: "main"},
%{key: "tests", label: "5484 passing"},
%{key: "mode", label: "INSERT"}
],
separator: " | "
})code_block
Syntax-highlighted code display. Uses Makeup for Elixir highlighting, falls back to plain text for other languages. Component module only.
alias Raxol.UI.Components.CodeBlock
{:ok, block} = CodeBlock.init(%{
content: ~s|defmodule Hello do\n def world, do: :ok\nend|,
language: "elixir"
})markdown_renderer
Renders markdown text with terminal formatting. Supports headings, bold, italic, inline code, lists, and blockquotes. Component module only.
alias Raxol.UI.Components.MarkdownRenderer
{:ok, md} = MarkdownRenderer.init(%{
markdown_text: "# Hello\n\nThis is **bold** and *italic*.\n\n- Item one\n- Item two",
width: 60
})Uses EarmarkParser when available, falls back to regex-based parsing.
image
Inline terminal image display. Supports Kitty, iTerm2, and Sixel protocols.
image(src: "logo.png", width: 30, height: 15)
image(src: raw_png_binary, protocol: :kitty, preserve_aspect: true)Options: protocol (:kitty, :iterm2, :sixel, auto-detected if omitted), preserve_aspect (default true).
Input
Components that accept user interaction. These handle keyboard events and fire callbacks.
button
Clickable button that sends a message to update/2 on press.
button("Save", on_click: :save)
button("Delete", on_click: {:delete, item.id})The component module (Raxol.UI.Components.Input.Button) supports: role (:primary, :secondary, :danger, :success), disabled, shortcut, tooltip.
Keyboard: Enter or Space to activate.
text_input
Single-line text input field.
text_input(value: model.name, placeholder: "Enter name...")The component module (Raxol.UI.Components.Input.TextInput) supports: on_change, on_submit, on_cancel, mask_char (for passwords), max_length, validator (function).
textarea
Multi-line text area.
textarea(
value: model.notes,
placeholder: "Write something...",
rows: 8
)For the full-featured editor with undo/redo, selection, and text wrapping, use the MultiLineInput component module directly.
checkbox
Toggle checkbox.
checkbox(checked: model.agreed, label: "I agree to the terms")The component module (Raxol.UI.Components.Input.Checkbox) supports: on_toggle, disabled, required, tooltip.
Keyboard: Space or Enter to toggle.
radio_group
Radio button group for single selection from a set of options.
radio_group(
options: ["Small", "Medium", "Large"],
selected: model.size
)Options: on_change.
select / select_list
Dropdown selection. The DSL select/1 creates a simple dropdown. The component module (Raxol.UI.Components.Input.SelectList) is a full-featured scrollable list with search, pagination, and multi-select.
# Simple DSL dropdown
select(
options: ["Elixir", "Rust", "Go"],
selected: model.language,
placeholder: "Pick a language..."
)# Full component with search and multi-select
alias Raxol.UI.Components.Input.SelectList
{:ok, sl} = SelectList.init(%{
id: "lang_picker",
options: [{"Elixir", :elixir}, {"Rust", :rust}, {"Go", :go}],
enable_search: true,
multiple: true,
max_height: 10,
on_select: :language_selected
})Keyboard: Up/Down (navigate), Enter (select), PageUp/PageDown, Home/End, type to search.
tabs
Tab navigation bar.
tabs(tabs: ["Overview", "Details", "Settings"], active: model.active_tab)The component module (Raxol.UI.Components.Input.Tabs) supports: on_change, keyboard Left/Right (with wrap), Home/End, 1-9 (direct select).
menu
Nested dropdown/context menu with submenus. Component module only.
alias Raxol.UI.Components.Input.Menu
items = [
%{id: :file, label: "File", children: [
%{id: :new, label: "New", shortcut: "Ctrl+N"},
%{id: :open, label: "Open", shortcut: "Ctrl+O"},
%{id: :save, label: "Save", shortcut: "Ctrl+S", disabled: true}
]},
%{id: :edit, label: "Edit", children: [
%{id: :undo, label: "Undo", shortcut: "Ctrl+Z"},
%{id: :redo, label: "Redo", shortcut: "Ctrl+Y"}
]}
]
{:ok, menu} = Menu.init(%{id: "main_menu", items: items, on_select: :menu_action})Keyboard: Up/Down (skip disabled items), Right (open submenu), Left (close submenu), Enter (select), Escape (close).
multi_line_input
Full text editor with undo/redo, selection, and word wrapping. Component module only.
alias Raxol.UI.Components.Input.MultiLineInput
{:ok, editor} = MultiLineInput.init(%{
id: "code_editor",
value: "defmodule Hello do\n def world, do: :ok\nend",
width: 60,
height: 20,
wrap: :word
})Options: wrap (:none, :char, :word), on_change, on_submit.
Features: cursor movement, shift-select, undo/redo history, line wrapping.
Overlay
Components that float above the main content.
modal
Modal dialog that overlays the current view.
# Simple alert
modal(visible: model.show_confirm, title: "Confirm", content: text("Delete this item?"))The component module (Raxol.UI.Components.Modal) supports multiple types:
alias Raxol.UI.Components.Modal
# Alert with buttons
{:ok, m} = Modal.init(%{
id: "confirm",
type: :alert,
title: "Delete Item",
content: "This cannot be undone.",
buttons: [
%{label: "Cancel", action: :cancel},
%{label: "Delete", action: :delete}
]
})
# Prompt with input
{:ok, m} = Modal.init(%{
id: "rename",
type: :prompt,
title: "Rename",
input_value: model.current_name
})
# Form with validation
{:ok, m} = Modal.init(%{
id: "settings",
type: :form,
title: "Settings",
fields: [%{name: "timeout", label: "Timeout (ms)"}],
validate: &validate_settings/1
})Progress Indicators
Show how far along something is, or that work is happening.
progress (DSL)
Standard horizontal progress bar. This is the DSL entry point.
progress(value: 65, max: 100)Progress.Bar, Progress.Spinner, Progress.Circular
Component modules for more control. Not separate DSL functions.
# Animated bar with percentage label
alias Raxol.UI.Components.Display.Progress
{:ok, bar} = Progress.init(%{
id: "upload",
progress: 0.65,
width: 40,
show_percentage: true,
label: "Uploading...",
animated: true
})# Spinner (stateless utility, call each frame)
alias Raxol.UI.Components.Progress.Spinner
# Available styles: :dots, :line, :circle, :arrow, :bounce,
# :pulse, :wave, :dots3, :square, :flip
frame = Spinner.spinner("Loading...", 0, type: :dots)| Module | Use case |
|---|---|
Progress.Bar | Determinate progress with known completion |
Progress.Spinner | Indeterminate: something is happening, unknown duration |
Progress.Circular | Circular/ring-style progress indicator |
Charts
Streaming data visualization. All chart functions render braille or block characters and compose naturally in view/1.
sparkline
Minimal inline chart: a line with no axes or legend.
sparkline(data: model.cpu_history, width: 30, height: 3, color: :green)line_chart
Braille line chart with multi-series support.
line_chart(
series: [
%{name: "CPU", data: model.cpu_history, color: :cyan},
%{name: "Memory", data: model.mem_history, color: :magenta}
],
width: 60,
height: 15,
show_axes: true,
show_legend: true
)bar_chart
Block-character bar chart. Vertical or horizontal, grouped multi-series.
bar_chart(
series: [
%{name: "Q1", data: [42, 67, 55], color: :blue},
%{name: "Q2", data: [50, 72, 61], color: :green}
],
width: 50,
height: 12,
orientation: :vertical,
show_values: true,
show_legend: true
)Options: bar_gap (gap within group), group_gap (gap between groups).
scatter_chart
Braille 2D scatter plot.
scatter_chart(
series: [
%{name: "Cluster A", data: [{1.2, 3.4}, {2.1, 4.5}, {1.8, 3.9}], color: :cyan},
%{name: "Cluster B", data: [{5.0, 1.2}, {4.8, 1.5}, {5.3, 0.9}], color: :yellow}
],
width: 50,
height: 15,
show_axes: true,
x_range: {0, 7},
y_range: {0, 6}
)heatmap
2D grid with color intensity.
heatmap(
data: [
[0.1, 0.4, 0.9, 0.6],
[0.3, 0.8, 0.5, 0.2],
[0.7, 0.2, 0.3, 0.8]
],
width: 40,
height: 6,
color_scale: :warm,
show_values: true
)Color scales: :warm (yellow -> red), :cool (cyan -> blue), :diverging (blue -> white -> red), or a custom fn(value, min, max) -> {r, g, b}.
Advanced
process_component
Run any component in its own supervised process for crash isolation. If it crashes, it restarts automatically without affecting the rest of the app.
# In your view:
process_component(MyExpensiveComponent, %{path: "/var/log"})focus_ring
Visual focus indicator for accessibility. Highlights the currently focused component.
Component module: Raxol.UI.Components.FocusRing
Options: color, width, offset, style (:solid), components (list of component IDs to track).
Using Components Directly
The View DSL functions cover most needs. When you need full control (handling events, managing component state, accessing all options) use the component modules directly:
alias Raxol.UI.Components.Input.TextInput
# Initialize with full options
{:ok, state} = TextInput.init(%{
id: "search",
value: "",
placeholder: "Search...",
max_length: 100,
on_submit: :do_search
})
# Handle an event
state = TextInput.handle_event(event, state, context)
# Render
rendered = TextInput.render(state, context)All component modules follow the same pattern: init/1 -> handle_event/3 -> render/2.
Quick Reference
| Component | DSL function | Module path | Interactive? |
|---|---|---|---|
| column | column do | -- | No |
| row | row do | -- | No |
| box | box do | -- | No |
| spacer | spacer/1 | -- | No |
| divider | divider/1 | -- | No |
| split_pane | split_pane/1 | UI.Layout.SplitPane | No |
| text | text/1 | -- | No |
| label | label/1 | -- | No |
| list | list/1 | -- | No |
| progress | progress/1 | Display.Progress | No |
| table | table/1 | Table | Yes |
| tree | -- | Display.Tree | Yes |
| viewport | -- | Display.Viewport | Yes |
| status_bar | -- | Display.StatusBar | No |
| code_block | -- | CodeBlock | No |
| markdown | -- | MarkdownRenderer | No |
| image | image/1 | -- | No |
| button | button/1 | Input.Button | Yes |
| text_input | text_input/1 | Input.TextInput | Yes |
| textarea | textarea/1 | Input.MultiLineInput | Yes |
| checkbox | checkbox/1 | Input.Checkbox | Yes |
| radio_group | radio_group/1 | -- | Yes |
| select | select/1 | Input.SelectList | Yes |
| tabs | tabs/1 | Input.Tabs | Yes |
| menu | -- | Input.Menu | Yes |
| modal | modal/1 | Modal | Yes |
| sparkline | sparkline/1 | -- | No |
| line_chart | line_chart/1 | -- | No |
| bar_chart | bar_chart/1 | -- | No |
| scatter_chart | scatter_chart/1 | -- | No |
| heatmap | heatmap/1 | -- | No |
| spinner | -- | Progress.Spinner | No |
| focus_ring | -- | FocusRing | No |
All component module paths are under Raxol.UI.Components.*.
Running Examples
# Interactive playground with all demos
mix raxol.playground
# Flagship demo (dashboard, sparklines, live stats)
mix run examples/demo.exs
# Simple starting point
mix run examples/getting_started/counter.exs
# Full Component showcase
mix run examples/apps/showcase_app.exs