Esc (Esc v0.9.0)

View Source

Declarative terminal styling for Elixir.

Esc provides an expressive API for styling terminal output with colors, borders, padding, margins, and text alignment.

Example

import Esc

style()
|> foreground(:red)
|> bold()
|> padding(1, 2)
|> border(:rounded)
|> render("Hello, World!")

Colors

Esc supports multiple color formats:

  • Named colors: :red, :green, :blue, :cyan, :magenta, :yellow, :white, :black
  • Bright variants: :bright_red, :bright_green, etc.
  • ANSI 256 palette: integers 0..255
  • True color: {r, g, b} tuples or hex strings like "#ff5733"

Borders

Available border styles: :normal, :rounded, :thick, :double, :hidden

Summary

Functions

Sets horizontal text alignment.

Sets the background color.

Enables blinking text.

Enables bold text.

Sets the border style.

Sets the border background color.

Enables or disables the bottom border.

Sets the border foreground color.

Enables or disables the left border.

Enables or disables the right border.

Enables or disables the top border.

Clears the current global theme.

Detects the color profile supported by the terminal.

Creates a copy of a style.

Sets a custom border with user-defined characters.

Enables faint/dim text.

Sets the foreground (text) color.

Returns the height (line count) of text.

Gets the current global theme, or nil if not set.

Returns the visible width of text, ignoring ANSI escape codes.

Detects if the terminal has a dark background.

Sets a fixed height for the output.

Inherits unset properties from another style.

Enables or disables inline mode.

Enables italic text.

Joins multiple text blocks horizontally (side by side).

Joins multiple text blocks vertically (stacked).

Sets margin on all sides.

Sets vertical and horizontal margin.

Sets margin for each side individually.

Sets the maximum height for rendered content.

Sets the maximum width for rendered content.

Enables or disables color output.

Sets padding on all sides.

Sets vertical and horizontal padding.

Sets padding for each side individually.

Places text within a box of specified dimensions.

Places text horizontally within a specified width.

Places text vertically within a specified height.

Renders text with the given style applied.

Sets a custom renderer function.

Enables reverse video (swap foreground/background).

Sets the global theme.

Enables strikethrough text.

Creates a new empty style.

Creates a new style with a theme attached.

Sets the tab width for tab-to-space conversion.

Sets background color from the current theme.

Sets border background color from the current theme.

Sets border foreground color from the current theme.

Gets a color from the current theme by name.

Sets foreground color from the current theme.

Lists all available built-in theme names.

Enables underlined text.

Removes the background color.

Disables blink.

Disables bold.

Removes the border.

Disables faint.

Removes the foreground color.

Removes the height constraint.

Disables italic.

Removes all margin.

Removes all padding.

Disables reverse.

Disables strikethrough.

Disables underline.

Removes the width constraint.

Sets vertical text alignment.

Sets a fixed width for the output.

Types

style()

@type style() :: Esc.Style.t()

Functions

align(s, alignment)

@spec align(style(), :left | :center | :right) :: style()

Sets horizontal text alignment.

background(s, color)

@spec background(style(), Esc.Style.color()) :: style()

Sets the background color.

When the style has a theme attached, color atoms are resolved to theme RGB values.

blink(s)

@spec blink(style()) :: style()

Enables blinking text.

bold(s)

@spec bold(style()) :: style()

Enables bold text.

border(s, style)

@spec border(style(), atom()) :: style()

Sets the border style.

Available styles: :normal, :rounded, :thick, :double, :hidden

border_background(s, color)

@spec border_background(style(), Esc.Style.color()) :: style()

Sets the border background color.

When the style has a theme attached, color atoms are resolved to theme RGB values.

border_bottom(s, enabled)

@spec border_bottom(style(), boolean()) :: style()

Enables or disables the bottom border.

border_foreground(s, color)

@spec border_foreground(style(), Esc.Style.color()) :: style()

Sets the border foreground color.

When the style has a theme attached, color atoms are resolved to theme RGB values.

border_left(s, enabled)

@spec border_left(style(), boolean()) :: style()

Enables or disables the left border.

border_right(s, enabled)

@spec border_right(style(), boolean()) :: style()

Enables or disables the right border.

border_top(s, enabled)

@spec border_top(style(), boolean()) :: style()

Enables or disables the top border.

clear_theme()

@spec clear_theme() :: :ok

Clears the current global theme.

After clearing, get_theme/0 will return nil (or fall back to Application config).

color_profile()

@spec color_profile() :: :no_color | :ansi | :ansi256 | :true_color

Detects the color profile supported by the terminal.

Returns one of:

  • :no_color - No color support (NO_COLOR env set or not a TTY)
  • :ansi - Basic 16 colors
  • :ansi256 - 256 color palette
  • :true_color - 24-bit true color

copy(s)

@spec copy(style()) :: style()

Creates a copy of a style.

Since Elixir data is immutable, this is technically just returning the same struct, but it's provided for API parity with Lipgloss.

custom_border(s, opts)

@spec custom_border(
  style(),
  keyword()
) :: style()

Sets a custom border with user-defined characters.

Options

  • :top - Top edge character
  • :bottom - Bottom edge character
  • :left - Left edge character
  • :right - Right edge character
  • :top_left - Top-left corner character
  • :top_right - Top-right corner character
  • :bottom_left - Bottom-left corner character
  • :bottom_right - Bottom-right corner character

Examples

style()
|> custom_border(
  top: "=",
  bottom: "=",
  left: "|",
  right: "|",
  top_left: "+",
  top_right: "+",
  bottom_left: "+",
  bottom_right: "+"
)
|> render("Custom box")

faint(s)

@spec faint(style()) :: style()

Enables faint/dim text.

foreground(s, color)

@spec foreground(style(), Esc.Style.color()) :: style()

Sets the foreground (text) color.

When the style has a theme attached, color atoms (:red, :bright_magenta, etc.) are resolved to the theme's RGB values. Without a theme, atoms pass through for standard ANSI rendering.

get_height(text)

@spec get_height(String.t()) :: non_neg_integer()

Returns the height (line count) of text.

Examples

iex> Esc.get_height("Single line")
1

iex> Esc.get_height("Line 1\nLine 2\nLine 3")
3

get_theme()

@spec get_theme() :: Esc.Theme.t() | nil

Gets the current global theme, or nil if not set.

Examples

Esc.set_theme(:nord)
Esc.get_theme()
#=> %Esc.Theme{name: :nord, ...}

get_width(text)

@spec get_width(String.t()) :: non_neg_integer()

Returns the visible width of text, ignoring ANSI escape codes.

For multiline text, returns the width of the widest line.

Examples

iex> Esc.get_width("Hello")
5

iex> Esc.get_width("Short\nMuch longer")
11

has_dark_background?()

@spec has_dark_background?() :: boolean()

Detects if the terminal has a dark background.

Returns true for dark backgrounds, false for light backgrounds. This is a best-effort detection and may not be accurate on all terminals.

height(s, h)

@spec height(style(), non_neg_integer()) :: style()

Sets a fixed height for the output.

inherit(s, base)

@spec inherit(style(), style()) :: style()

Inherits unset properties from another style.

Only properties that are at their default values in the current style will be inherited from the base style.

Examples

base = style() |> foreground(:red) |> bold()
derived = style() |> foreground(:blue) |> inherit(base)
# derived has blue foreground (not inherited) and bold (inherited)

inline(s, enabled)

@spec inline(style(), boolean()) :: style()

Enables or disables inline mode.

In inline mode:

  • Newlines are stripped from content
  • Width and height constraints are ignored

italic(s)

@spec italic(style()) :: style()

Enables italic text.

join_horizontal(blocks, align \\ :top)

@spec join_horizontal([String.t()], :top | :middle | :bottom) :: String.t()

Joins multiple text blocks horizontally (side by side).

Options

The second argument specifies vertical alignment:

  • :top (default) - Align blocks to the top
  • :middle - Center blocks vertically
  • :bottom - Align blocks to the bottom

Examples

left = "A\nB"
right = "1\n2"
Esc.join_horizontal([left, right])
# "A1\nB2"

join_vertical(blocks, align \\ :left)

@spec join_vertical([String.t()], :left | :center | :right) :: String.t()

Joins multiple text blocks vertically (stacked).

Options

The second argument specifies horizontal alignment:

  • :left (default) - Align blocks to the left
  • :center - Center blocks horizontally
  • :right - Align blocks to the right

Examples

top = "AAA"
bottom = "B"
Esc.join_vertical([top, bottom], :center)
# "AAA\n B "

margin(s, all)

@spec margin(style(), non_neg_integer()) :: style()

Sets margin on all sides.

margin(s, vertical, horizontal)

@spec margin(style(), non_neg_integer(), non_neg_integer()) :: style()

Sets vertical and horizontal margin.

margin(s, top, right, bottom, left)

Sets margin for each side individually.

max_height(s, height)

@spec max_height(style(), non_neg_integer()) :: style()

Sets the maximum height for rendered content.

Content exceeding this height will be truncated.

max_width(s, width)

@spec max_width(style(), non_neg_integer()) :: style()

Sets the maximum width for rendered content.

Content exceeding this width will be truncated.

no_color(s, enabled)

@spec no_color(style(), boolean()) :: style()

Enables or disables color output.

When disabled, all ANSI color codes are stripped from output. Layout (borders, padding) is preserved.

padding(s, all)

@spec padding(style(), non_neg_integer()) :: style()

Sets padding on all sides.

padding(s, vertical, horizontal)

@spec padding(style(), non_neg_integer(), non_neg_integer()) :: style()

Sets vertical and horizontal padding.

padding(s, top, right, bottom, left)

Sets padding for each side individually.

place(width, height, h_align, v_align, text)

@spec place(
  non_neg_integer(),
  non_neg_integer(),
  :left | :center | :right,
  :top | :middle | :bottom,
  String.t()
) :: String.t()

Places text within a box of specified dimensions.

Examples

Esc.place(20, 5, :center, :middle, "X")
# Returns a 20x5 box with "X" centered

place_horizontal(width, align, text)

@spec place_horizontal(non_neg_integer(), :left | :center | :right, String.t()) ::
  String.t()

Places text horizontally within a specified width.

Examples

Esc.place_horizontal(20, :center, "Hi")
# "         Hi         "

place_vertical(height, align, text)

@spec place_vertical(non_neg_integer(), :top | :middle | :bottom, String.t()) ::
  String.t()

Places text vertically within a specified height.

Examples

Esc.place_vertical(5, :middle, "X")
# Returns 5 lines with "X" on the middle line

render(style, text)

@spec render(style(), String.t()) :: String.t()

Renders text with the given style applied.

renderer(s, render_fn)

@spec renderer(style(), (String.t(), Esc.Style.t() -> String.t())) :: style()

Sets a custom renderer function.

The renderer receives the text and style, and returns the rendered output.

Examples

upcase_renderer = fn text, _style -> String.upcase(text) end

style()
|> renderer(upcase_renderer)
|> render("hello")
# "HELLO"

reverse(s)

@spec reverse(style()) :: style()

Enables reverse video (swap foreground/background).

set_theme(theme)

@spec set_theme(atom() | Esc.Theme.t()) :: :ok | {:error, :unknown_theme}

Sets the global theme.

Themes provide a consistent color palette including 16 ANSI colors, background/foreground colors, and semantic colors for common UI purposes.

Examples

Esc.set_theme(:nord)
Esc.set_theme(:dracula)

Available Themes

:dracula, :nord, :gruvbox, :one, :solarized, :monokai, :material, :github, :aura, :dolphin, :chalk, :cobalt

strikethrough(s)

@spec strikethrough(style()) :: style()

Enables strikethrough text.

style()

@spec style() :: style()

Creates a new empty style.

style(theme_name)

@spec style(atom() | Esc.Theme.t()) :: style()

Creates a new style with a theme attached.

When a theme is attached, color atoms (:red, :bright_magenta, etc.) are resolved to the theme's RGB values instead of standard ANSI codes.

Examples

# With theme name
style(:nord) |> foreground(:red) |> render("Error")

# With theme struct
theme = Esc.Theme.Palette.get(:dracula)
style(theme) |> foreground(:cyan) |> render("Info")

tab_width(s, width)

@spec tab_width(style(), non_neg_integer()) :: style()

Sets the tab width for tab-to-space conversion.

A value of 0 preserves tabs as-is. Default is 4.

theme_background(s, color_name)

@spec theme_background(style(), atom()) :: style()

Sets background color from the current theme.

If no theme is set or the color is not defined, the style is unchanged.

Examples

style() |> theme_background(:success) |> render("Success!")

theme_border_background(s, color_name)

@spec theme_border_background(style(), atom()) :: style()

Sets border background color from the current theme.

If no theme is set or the color is not defined, the style is unchanged.

theme_border_foreground(s, color_name)

@spec theme_border_foreground(style(), atom()) :: style()

Sets border foreground color from the current theme.

If no theme is set or the color is not defined, the style is unchanged.

Examples

style() |> border(:rounded) |> theme_border_foreground(:muted) |> render("Box")

theme_color(name)

@spec theme_color(atom()) :: Esc.Style.color() | nil

Gets a color from the current theme by name.

Returns nil if no theme is set or the color is not defined.

Semantic Colors

  • :header - Headers, titles (defaults to cyan)
  • :emphasis - Important text (defaults to blue)
  • :warning - Warning messages (defaults to yellow)
  • :error - Error messages (defaults to red)
  • :success - Success messages (defaults to green)
  • :muted - Subdued text, borders (defaults to gray)

ANSI Colors

:ansi_0 through :ansi_15, :background, :foreground

Examples

Esc.set_theme(:nord)
Esc.theme_color(:error)
#=> {191, 97, 106}

theme_foreground(s, color_name)

@spec theme_foreground(style(), atom()) :: style()

Sets foreground color from the current theme.

If no theme is set or the color is not defined, the style is unchanged.

Examples

style() |> theme_foreground(:error) |> render("Error!")

themes()

@spec themes() :: [atom()]

Lists all available built-in theme names.

Examples

Esc.themes()
#=> [:dracula, :nord, :gruvbox, :one, :solarized, :monokai,
#    :material, :github, :aura, :dolphin, :chalk, :cobalt]

underline(s)

@spec underline(style()) :: style()

Enables underlined text.

unset_background(s)

@spec unset_background(style()) :: style()

Removes the background color.

unset_blink(s)

@spec unset_blink(style()) :: style()

Disables blink.

unset_bold(s)

@spec unset_bold(style()) :: style()

Disables bold.

unset_border(s)

@spec unset_border(style()) :: style()

Removes the border.

unset_faint(s)

@spec unset_faint(style()) :: style()

Disables faint.

unset_foreground(s)

@spec unset_foreground(style()) :: style()

Removes the foreground color.

unset_height(s)

@spec unset_height(style()) :: style()

Removes the height constraint.

unset_italic(s)

@spec unset_italic(style()) :: style()

Disables italic.

unset_margin(s)

@spec unset_margin(style()) :: style()

Removes all margin.

unset_padding(s)

@spec unset_padding(style()) :: style()

Removes all padding.

unset_reverse(s)

@spec unset_reverse(style()) :: style()

Disables reverse.

unset_strikethrough(s)

@spec unset_strikethrough(style()) :: style()

Disables strikethrough.

unset_underline(s)

@spec unset_underline(style()) :: style()

Disables underline.

unset_width(s)

@spec unset_width(style()) :: style()

Removes the width constraint.

vertical_align(s, alignment)

@spec vertical_align(style(), :top | :middle | :bottom) :: style()

Sets vertical text alignment.

width(s, w)

@spec width(style(), non_neg_integer()) :: style()

Sets a fixed width for the output.