ExRatatui.Theme (ExRatatui v0.11.0)

Copy Markdown View Source

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; nil means "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.

Returns a light-terminal-friendly variant of default/0.

Builds a selection-highlight %Style{} from a theme.

Builds a body-text %Style{} from a theme.

Types

t()

@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

border_style(theme, opts \\ [])

@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: []}

default()

@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

light()

@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

selection_style(theme)

@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: []}

text_style(theme, opts \\ [])

@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: []}