Named-slot color palette for TUI apps.
A %Theme{} is a pure data struct — a map from semantic slot names
(:accent, :border, :success, …) to ExRatatui.Style.color/0
values. Apps build %Style{} values from it via the helpers below
(border_style/2, text_style/2, selection_style/1) or by
destructuring slots directly into widget fields.
This is "Layer A" of the theming work: pure data the app threads
through its render code by hand. There is no automatic widget
injection — Block borders don't magically pick up theme.border
unless the app passes it in. A later "Layer B" may add an opt-in
pass that merges theme defaults into widget structs at render time;
Layer A stays explicit and dependency-free.
Slots
:primary— main brand color (titles, highlighted headers):accent— interactive / focused / selected elements:border— default border color for unfocused panels:border_focused— border color for the focused panel:surface— primary background;nilmeans "let the terminal decide" and works on both light and dark terminals:surface_alt— secondary background (alt rows in tables, striped lists, raised panels):text— default foreground for body text:text_dim— secondary foreground (hints, placeholders, disabled controls):success/:warning/:danger— status messages and severity indicators
Every slot accepts the full ExRatatui.Style.color/0 shape:
named atoms (:cyan, :dark_gray), {:rgb, r, g, b},
{:indexed, n}, or nil. Slots default to nil, meaning "fall
back to the terminal default" — apps that don't want to depend on
any particular palette can drop unused slots.
Composing with widgets
theme = ExRatatui.Theme.default()
%ExRatatui.Widgets.Block{
title: "Search",
borders: [:all],
border_style: ExRatatui.Theme.border_style(theme, focused: focused?)
}
%ExRatatui.Widgets.List{
items: results,
highlight_style: ExRatatui.Theme.selection_style(theme)
}Picking a theme
Two starter constructors ship in the box:
default/0— terminal-respecting dark-friendly palette (cyan accent, transparent surface)light/0— same shape with darker text and a light surface, suitable for light terminal themes
Apps with stricter brand requirements compose their own:
%ExRatatui.Theme{
primary: {:rgb, 88, 28, 135},
accent: {:rgb, 245, 158, 11},
border: :gray,
border_focused: {:rgb, 245, 158, 11},
text: :white,
text_dim: :gray,
success: :green,
warning: :yellow,
danger: :red
}
Summary
Functions
Builds a border %Style{} from a theme.
Returns a terminal-respecting dark-friendly default theme.
Builds a selection-highlight %Style{} from a theme.
Builds a body-text %Style{} from a theme.
Types
@type t() :: %ExRatatui.Theme{ accent: ExRatatui.Style.color() | nil, border: ExRatatui.Style.color() | nil, border_focused: ExRatatui.Style.color() | nil, danger: ExRatatui.Style.color() | nil, primary: ExRatatui.Style.color() | nil, success: ExRatatui.Style.color() | nil, surface: ExRatatui.Style.color() | nil, surface_alt: ExRatatui.Style.color() | nil, text: ExRatatui.Style.color() | nil, text_dim: ExRatatui.Style.color() | nil, warning: ExRatatui.Style.color() | nil }
Functions
@spec border_style( t(), keyword() ) :: ExRatatui.Style.t()
Builds a border %Style{} from a theme.
Accepts focused: true to swap in :border_focused. Defaults to the
unfocused :border slot.
Examples
iex> theme = ExRatatui.Theme.default()
iex> ExRatatui.Theme.border_style(theme)
%ExRatatui.Style{fg: :gray, bg: nil, modifiers: []}
iex> ExRatatui.Theme.border_style(theme, focused: true)
%ExRatatui.Style{fg: :cyan, bg: nil, modifiers: []}
@spec default() :: t()
Returns a terminal-respecting dark-friendly default theme.
Surfaces are nil so the terminal's own background shows through —
works on both light and dark terminal themes without forcing one.
Accent is cyan, borders are gray with cyan-on-focus, status uses the
conventional green / yellow / red triad.
Examples
iex> theme = ExRatatui.Theme.default()
iex> theme.accent
:cyan
iex> theme.surface
nil
@spec light() :: t()
Returns a light-terminal-friendly variant of default/0.
Text is dark, surface is white, accent stays cyan but borders shift to dark_gray for contrast on a light background.
Examples
iex> theme = ExRatatui.Theme.light()
iex> theme.text
:black
iex> theme.surface
:white
@spec selection_style(t()) :: ExRatatui.Style.t()
Builds a selection-highlight %Style{} from a theme.
The convention is a reversed-style pop: the theme's :surface color
becomes the foreground, the :accent becomes the background. Use on
List :highlight_style, Table :highlight_style, selected Tabs,
etc.
Examples
iex> theme = ExRatatui.Theme.default()
iex> ExRatatui.Theme.selection_style(theme)
%ExRatatui.Style{fg: nil, bg: :cyan, modifiers: []}
@spec text_style( t(), keyword() ) :: ExRatatui.Style.t()
Builds a body-text %Style{} from a theme.
Accepts dim: true to use the :text_dim slot (hints, placeholders,
disabled). The background is always theme.surface, which is nil
in the default theme.
Examples
iex> theme = ExRatatui.Theme.default()
iex> ExRatatui.Theme.text_style(theme)
%ExRatatui.Style{fg: :white, bg: nil, modifiers: []}
iex> ExRatatui.Theme.text_style(theme, dim: true)
%ExRatatui.Style{fg: :gray, bg: nil, modifiers: []}