# Rich — User Guide

Rich is a Python library for rich text and beautiful formatting in the terminal. It provides an extensive toolkit for building polished command-line interfaces: styled text with colors and formatting, tables with borders and alignment, progress bars, syntax highlighting, Markdown rendering, pretty-printed data structures, enhanced tracebacks, tree views, panels, layouts, live-updating displays, logging integration, and more. Rich works with any terminal that supports ANSI escape codes and automatically adapts its output to the capabilities of the environment -- from 4-bit color all the way to 24-bit truecolor, with automatic downgrade for limited terminals.

---

## 1. Quick Start

Get Rich installed and printing styled output in under a minute.

### Install and verify

```bash
pip install rich
```

Verify the installation by running the built-in test card, which demonstrates most of Rich's features in a single output:

```bash
python -m rich
```

You should see a colorful display showcasing colors, styles, text justification, markup, tables, syntax highlighting, pretty printing, Markdown, and more.

### Your first Rich print

```python
from rich import print

print("Hello, [bold magenta]World[/bold magenta]!")
```

That single import replaces Python's built-in `print()` with Rich's version, which understands BBCode-like markup for inline styling. The output renders "World" in bold magenta.

### A quick table

```python
from rich.console import Console
from rich.table import Table

table = Table(title="Grocery List")
table.add_column("Item", style="cyan")
table.add_column("Qty", justify="right", style="green")

table.add_row("Apples", "6")
table.add_row("Bread", "1")
table.add_row("Milk", "2")

console = Console()
console.print(table)
```

> [!TIP]
> Run `python -m rich` at any time to see a comprehensive demo of Rich's capabilities. It is the fastest way to confirm your terminal supports Rich output and to see what is available.

---

## 2. Installation

### Requirements

| Requirement | Detail |
|---|---|
| Python | 3.8 or later |
| OS | Linux, macOS, Windows (Windows Terminal recommended) |
| Dependencies | `pygments` (syntax highlighting), `markdown-it-py` (Markdown parsing) -- installed automatically by pip |

### Install from PyPI

```bash
pip install rich
```

Or with your preferred package manager:

```bash
# Poetry
poetry add rich

# Conda
conda install -c conda-forge rich

# pipx (for CLI utilities that use Rich)
pipx install rich
```

### Development install

```bash
git clone https://github.com/Textualize/rich.git
cd rich
pip install -e ".[dev]"
```

> [!IMPORTANT]
> On Windows, use **Windows Terminal** for the best experience. The legacy `cmd.exe` console has limited color support. Rich auto-detects terminal capabilities and degrades gracefully, but colors and Unicode rendering will be reduced in older terminals.

### Verify installation

```python
>>> import rich
>>> rich.print("[green]Rich is working![/green]")
```

If you see green text, Rich is installed and your terminal supports styled output.

---

## 3. Configuration

Rich requires no configuration files. All behavior is controlled through Python constructor arguments and a small number of environment variables.

### Environment variables

| Variable | Default | Purpose |
|---|---|---|
| `UNICODE_VERSION` | `latest` | Override the Unicode version used for character width calculation. Set to a specific version (e.g., `13.0.0`) if your terminal renders certain characters at unexpected widths. |
| `DATABRICKS_RUNTIME_VERSION` | *(unset)* | Automatically detected. When present, Rich adjusts its behavior for Databricks notebook environments. |
| `NO_COLOR` | *(unset)* | Industry standard. When set to any value, Rich disables all color output. See [no-color.org](https://no-color.org). |
| `TERM` | *(varies)* | Rich reads the standard `TERM` variable to determine terminal capabilities. Setting `TERM=dumb` forces plain-text output. |
| `COLUMNS` | *(auto)* | Override the detected terminal width. Useful for CI or piped output. |
| `FORCE_COLOR` | *(unset)* | When set, forces Rich to output color even when the output is not a TTY. |

### Console configuration

The `Console` class is the central object in Rich. Most configuration happens at construction time:

```python
from rich.console import Console

# Default: auto-detect everything
console = Console()

# Force a specific width (useful for testing or file output)
console = Console(width=120)

# Disable color
console = Console(no_color=True)

# Force terminal mode for non-TTY output (e.g., piping to a file)
console = Console(force_terminal=True)

# Write to stderr instead of stdout
console = Console(stderr=True)

# Use a custom file object
console = Console(file=open("output.txt", "w"))

# Enable recording for later export
console = Console(record=True)
```

Key `Console` constructor parameters:

| Parameter | Type | Default | Description |
|---|---|---|---|
| `color_system` | `str` or `None` | `"auto"` | Force color system: `"standard"` (4-bit), `"256"` (8-bit), `"truecolor"` (24-bit), `"windows"`, or `None` to disable |
| `force_terminal` | `bool` | `False` | Treat output as a terminal even if not a TTY |
| `force_jupyter` | `bool` | `False` | Force Jupyter notebook rendering |
| `width` | `int` | *(auto)* | Override terminal width |
| `height` | `int` | *(auto)* | Override terminal height |
| `no_color` | `bool` | `False` | Disable all color |
| `tab_size` | `int` | `8` | Number of spaces per tab |
| `record` | `bool` | `False` | Enable output recording for export |
| `markup` | `bool` | `True` | Enable Rich markup parsing |
| `emoji` | `bool` | `True` | Enable emoji shortcode rendering |
| `highlight` | `bool` | `True` | Enable automatic highlighting |
| `log_time` | `bool` | `True` | Show timestamp in `console.log()` |
| `log_path` | `bool` | `True` | Show file path in `console.log()` |

### Reconfiguring the global console

Rich maintains a global `Console` instance used by `rich.print()`. You can reconfigure it:

```python
from rich import reconfigure

reconfigure(width=100, no_color=True)
```

### Themes

Rich supports custom themes for consistent styling across your application:

```python
from rich.console import Console
from rich.theme import Theme

custom_theme = Theme({
    "info": "dim cyan",
    "warning": "magenta",
    "danger": "bold red",
})

console = Console(theme=custom_theme)
console.print("This is [info]information[/info]")
console.print("This is [warning]a warning[/warning]")
console.print("This is [danger]dangerous[/danger]")
```

Themes can also be loaded from INI-style config files:

```ini
# mytheme.ini
[styles]
info = dim cyan
warning = magenta
danger = bold red
```

```python
from rich.theme import Theme
theme = Theme.read("mytheme.ini")
```

---

## 4. Core Usage

### 4.1 Printing Styled Text

#### The `rich.print()` drop-in replacement

```python
from rich import print

print("Hello, [bold red]World[/bold red]!")
print("[underline]Underlined[/underline] and [strike]strikethrough[/strike]")
print("[on blue]White on blue background[/on blue]")
print(":thumbs_up: Emoji support with shortcodes")
```

`rich.print()` has the same signature as the built-in `print()` -- `sep`, `end`, `file`, and `flush` all work as expected.

#### Rich markup syntax

Rich uses a BBCode-like markup for inline styling. Tags are enclosed in square brackets:

| Markup | Effect |
|---|---|
| `[bold]text[/bold]` | **Bold** |
| `[italic]text[/italic]` | *Italic* |
| `[underline]text[/underline]` | Underlined |
| `[strike]text[/strike]` | Strikethrough |
| `[dim]text[/dim]` | Dimmed |
| `[reverse]text[/reverse]` | Reversed foreground/background |
| `[blink]text[/blink]` | Blinking (terminal support varies) |
| `[red]text[/red]` | Named color |
| `[#ff8800]text[/#ff8800]` | Hex color |
| `[on blue]text[/on blue]` | Background color |
| `[bold red on white]text[/]` | Combined styles, closed with `[/]` |
| `[link=URL]text[/link]` | Clickable hyperlink (terminal support varies) |

> [!TIP]
> Use `[/]` as a shorthand to close *all* open tags. You can also use short forms: `[b]` for bold, `[i]` for italic, `[u]` for underline.

#### The Console class

For full control, use `Console` directly:

```python
from rich.console import Console

console = Console()

# Basic printing with styles
console.print("Hello", style="bold green")

# Logging with timestamp and file path
console.log("Server started", style="info")

# Print a rule (horizontal line)
console.rule("[bold blue]Section Header")

# Print with justification
console.print("Centered text", justify="center")
console.print("Right-aligned", justify="right")
```

#### Text objects for fine-grained control

```python
from rich.text import Text

text = Text("Hello, World!")
text.stylize("bold", 0, 5)           # "Hello" is bold
text.stylize("red", 7, 12)           # "World" is red
text.highlight_regex(r"\w+", "cyan") # Highlight all words

console.print(text)
```

You can also construct `Text` from markup:

```python
text = Text.from_markup("[bold]Hello[/], [italic red]World[/]!")
```

#### Style objects

```python
from rich.style import Style

warning_style = Style(bold=True, color="yellow", bgcolor="red")
console.print("WARNING!", style=warning_style)

# Parse from string
style = Style.parse("bold italic cyan on dark_blue")
```

> [!NOTE]
> Rich supports 16 standard color names (`red`, `green`, `blue`, etc.), 256 extended colors via `color(N)` syntax, and 24-bit truecolor via `rgb(R,G,B)` or hex `#RRGGBB`. Rich automatically converts colors to the best available representation for the current terminal.

### 4.2 Tables

Rich renders tables with borders, colors, column alignment, and automatic sizing.

#### Basic table

```python
from rich.console import Console
from rich.table import Table

table = Table(title="Star Wars Movies")

table.add_column("Released", style="cyan", no_wrap=True)
table.add_column("Title", style="magenta")
table.add_column("Box Office", justify="right", style="green")

table.add_row("Dec 20, 2019", "Star Wars: The Rise of Skywalker", "$952,110,690")
table.add_row("May 25, 2018", "Solo: A Star Wars Story", "$393,151,347")
table.add_row("Dec 15, 2017", "Star Wars Ep. VIII: The Last Jedi", "$1,332,539,889")
table.add_row("Dec 16, 2016", "Rogue One: A Star Wars Story", "$1,332,439,889")

console = Console()
console.print(table)
```

#### Table configuration

| Parameter | Type | Default | Description |
|---|---|---|---|
| `title` | `str` | `None` | Title displayed above the table |
| `caption` | `str` | `None` | Caption displayed below the table |
| `box` | `Box` | `HEAVY_HEAD` | Border style (see `rich.box` module) |
| `show_header` | `bool` | `True` | Show column headers |
| `show_footer` | `bool` | `False` | Show column footers |
| `show_edge` | `bool` | `True` | Show table border |
| `show_lines` | `bool` | `False` | Show lines between rows |
| `expand` | `bool` | `False` | Expand table to fill available width |
| `padding` | `int/tuple` | `(0, 1)` | Cell padding |
| `row_styles` | `list` | `None` | Alternating row styles, e.g. `["none", "dim"]` |

#### Column options

```python
table.add_column(
    "Name",
    justify="left",      # "left", "center", "right", "full"
    style="cyan",         # Default cell style
    header_style="bold",  # Header cell style
    no_wrap=True,         # Prevent word wrapping
    ratio=2,              # Relative width ratio
    min_width=10,         # Minimum column width
    max_width=30,         # Maximum column width
    overflow="ellipsis",  # Overflow handling
)
```

#### Grid layout (borderless tables)

`Table.grid()` creates a borderless table useful for layouts:

```python
table = Table.grid(padding=1, pad_edge=True)
table.add_column("Label", style="bold", justify="right")
table.add_column("Value")
table.add_row("Name:", "Rich")
table.add_row("Version:", "13.x")
table.add_row("Author:", "Will McGugan")
console.print(table)
```

#### Box styles

Rich includes many border styles in `rich.box`:

```python
from rich import box

table = Table(box=box.ROUNDED)    # Rounded corners
table = Table(box=box.SIMPLE)     # Simple lines
table = Table(box=box.MINIMAL)    # Minimal borders
table = Table(box=box.DOUBLE)     # Double-line borders
table = Table(box=None)           # No borders at all
```

### 4.3 Progress Bars

#### Simple progress with `track()`

The easiest way to add a progress bar:

```python
from rich.progress import track

for item in track(range(100), description="Processing..."):
    # do work
    pass
```

#### The Progress class

For more control, use the `Progress` context manager:

```python
from rich.progress import Progress

with Progress() as progress:
    task = progress.add_task("[green]Downloading...", total=1000)
    while not progress.finished:
        progress.update(task, advance=1)
```

#### Multi-task progress

```python
from rich.progress import Progress

with Progress() as progress:
    task1 = progress.add_task("[red]Downloading...", total=1000)
    task2 = progress.add_task("[green]Processing...", total=500)
    task3 = progress.add_task("[cyan]Cooking...", total=200)

    while not progress.finished:
        progress.update(task1, advance=0.9)
        progress.update(task2, advance=0.5)
        progress.update(task3, advance=0.3)
```

#### Custom progress columns

```python
from rich.progress import (
    BarColumn,
    DownloadColumn,
    Progress,
    TextColumn,
    TimeRemainingColumn,
    TransferSpeedColumn,
)

progress = Progress(
    TextColumn("[bold blue]{task.fields[filename]}", justify="right"),
    BarColumn(bar_width=None),
    "[progress.percentage]{task.percentage:>3.1f}%",
    DownloadColumn(),
    TransferSpeedColumn(),
    TimeRemainingColumn(),
)
```

Available built-in columns:

| Column | Description |
|---|---|
| `TextColumn` | Arbitrary text with task field interpolation |
| `BarColumn` | The progress bar itself |
| `SpinnerColumn` | An animated spinner |
| `TimeElapsedColumn` | Time since task started |
| `TimeRemainingColumn` | Estimated time remaining |
| `DownloadColumn` | Download progress in bytes/KB/MB/GB |
| `TransferSpeedColumn` | Transfer speed |
| `FileSizeColumn` | Total file size |
| `MofNCompleteColumn` | "M of N" style counter |
| `TaskProgressColumn` | Percentage complete |

#### File copy with progress

```python
import shutil
from rich.progress import Progress

with Progress() as progress:
    desc = "Copying data.bin"
    with progress.open("data.bin", "rb", description=desc) as src:
        with open("data_copy.bin", "wb") as dst:
            shutil.copyfileobj(src, dst)
```

> [!NOTE]
> `progress.open()` wraps a file object to automatically track read progress. There is also `progress.wrap_file()` for wrapping arbitrary file-like objects (e.g., HTTP response streams).

#### Deferred task start

For downloads where you don't know the total size upfront:

```python
task_id = progress.add_task("download", filename="data.zip", start=False)
# ... later, when you know the size:
progress.update(task_id, total=file_size)
progress.start_task(task_id)
```

### 4.4 Syntax Highlighting

Rich highlights source code using Pygments, with added features like line numbers and indent guides.

```python
from rich.syntax import Syntax

code = '''
def hello(name: str) -> None:
    """Greet someone."""
    print(f"Hello, {name}!")
'''

syntax = Syntax(code, "python", theme="monokai", line_numbers=True)
console.print(syntax)
```

#### Load from file

```python
syntax = Syntax.from_path("example.py", line_numbers=True, indent_guides=True)
console.print(syntax)
```

#### Syntax constructor options

| Parameter | Type | Default | Description |
|---|---|---|---|
| `code` | `str` | *(required)* | Source code string |
| `lexer` | `str` | *(required)* | Pygments lexer name (`"python"`, `"javascript"`, etc.) |
| `theme` | `str` | `"monokai"` | Pygments theme name |
| `line_numbers` | `bool` | `False` | Display line numbers |
| `start_line` | `int` | `1` | Starting line number |
| `line_range` | `tuple` | `None` | Only show lines in `(start, end)` range |
| `highlight_lines` | `set` | `None` | Set of line numbers to highlight |
| `word_wrap` | `bool` | `False` | Wrap long lines |
| `indent_guides` | `bool` | `False` | Show indent guide lines |
| `padding` | `int` | `0` | Padding around code |
| `background_color` | `str` | `None` | Override background color |

#### CLI utility

```bash
# Highlight a file in the terminal
python -m rich.syntax example.py --line-numbers --indent-guides --theme monokai
```

### 4.5 Markdown Rendering

Rich renders Markdown directly in the terminal:

```python
from rich.markdown import Markdown

md = Markdown("""
# Heading 1

This is **bold** and *italic* text with `inline code`.

- Item one
- Item two
- Item three

```python
print("Hello from a code block!")
```
""")

console.print(md)
```

#### Markdown options

| Parameter | Type | Default | Description |
|---|---|---|---|
| `markup` | `str` | *(required)* | Markdown text |
| `code_theme` | `str` | `"monokai"` | Pygments theme for code blocks |
| `inline_code_lexer` | `str` | `None` | Lexer for inline code |
| `hyperlinks` | `bool` | `True` | Render clickable links (if terminal supports) |
| `justify` | `str` | `None` | Text justification |

#### CLI utility

```bash
# Render a markdown file in the terminal
python -m rich.markdown README.md --force-color --width 80

# With a specific code theme
python -m rich.markdown README.md --code-theme dracula
```

### 4.6 Pretty Printing

Rich's pretty printer displays Python data structures with indentation, syntax coloring, and smart wrapping.

#### Quick install for the REPL

```python
from rich.pretty import install
install()
```

After calling `install()`, every expression result in the Python REPL is automatically pretty-printed. This is one of the most popular Rich features for interactive development.

#### Explicit pretty printing

```python
from rich.pretty import pprint

data = {
    "name": "Rich",
    "features": ["colors", "tables", "progress bars"],
    "nested": {"level1": {"level2": [1, 2, 3]}},
}
pprint(data, indent_guides=True, expand_all=True)
```

#### Pretty as a renderable

```python
from rich.pretty import Pretty
from rich.panel import Panel

data = {"key": [1, 2, 3], "other": ("a", "b", "c")}
console.print(Panel(Pretty(data), title="Data"))
```

#### Auto-repr with `@rich.repr.auto`

Automatically generate a Rich-compatible `__repr__` for your classes:

```python
import rich.repr

@rich.repr.auto
class Bird:
    def __init__(self, name, eats=None, fly=True, extinct=False):
        self.name = name
        self.eats = list(eats) if eats else []
        self.fly = fly
        self.extinct = extinct

from rich import print
print(Bird("penguin", eats=["fish"], fly=False))
```

> [!TIP]
> Use `rich.pretty.install()` in your Python startup file (`PYTHONSTARTUP` environment variable) to get Rich pretty printing in every interactive session automatically.

### 4.7 Tracebacks

Rich produces tracebacks with syntax highlighting, local variable display, and cleaner formatting than Python's default.

#### Global install (recommended for applications)

```python
from rich.traceback import install
install(show_locals=True)

# Now ALL unhandled exceptions use Rich tracebacks automatically
```

#### Manual exception printing

```python
from rich.console import Console

console = Console()

try:
    1 / 0
except Exception:
    console.print_exception(show_locals=True)
```

#### `install()` options

| Parameter | Type | Default | Description |
|---|---|---|---|
| `show_locals` | `bool` | `False` | Show local variables in each frame |
| `width` | `int` | `100` | Width of traceback output |
| `extra_lines` | `int` | `3` | Extra lines of code context around the error |
| `theme` | `str` | `None` | Pygments theme for code |
| `word_wrap` | `bool` | `False` | Wrap long lines |
| `suppress` | `list` | `[]` | List of modules/paths to suppress from tracebacks |
| `max_frames` | `int` | `100` | Maximum frames to show (useful for recursion errors) |

#### Suppressing library frames

```python
from rich.traceback import install
import click

install(suppress=[click])
# Click's internal frames will be dimmed in tracebacks
```

> [!WARNING]
> When using Rich tracebacks with `show_locals=True`, be aware that local variable values are displayed in the traceback output. Avoid logging tracebacks that may contain sensitive data (passwords, tokens, API keys) to shared locations.

### 4.8 Trees

Display hierarchical data as an expandable tree:

```python
from rich.tree import Tree

tree = Tree("Root")
branch1 = tree.add("Branch 1")
branch1.add("Leaf 1a")
branch1.add("Leaf 1b")
branch2 = tree.add("Branch 2")
branch2.add("[red]Leaf 2a[/red]")
sub = branch2.add("Sub-branch")
sub.add("Deep leaf")

console.print(tree)
```

Trees can contain any Rich renderable, including tables, panels, and syntax blocks:

```python
from rich.tree import Tree
from rich.syntax import Syntax

tree = Tree("Project")
src = tree.add("src/")
src.add(Syntax("def main(): pass", "python"))
```

### 4.9 Panels and Layout

#### Panels

Wrap any content in a bordered panel:

```python
from rich.panel import Panel

console.print(Panel("Hello, World!", title="Greeting", border_style="green"))
console.print(Panel.fit("Tight fit panel", border_style="red"))
```

Panel options include `title`, `subtitle`, `border_style`, `padding`, `expand`, and `box` (border style).

#### Alignment

```python
from rich.align import Align

console.print(Align.center("Centered text"))
console.print(Align.right("Right-aligned"))
console.print(Align.center("Vertically centered", vertical="middle"))
```

#### Columns

Display items in auto-sized columns:

```python
from rich.columns import Columns
from rich.panel import Panel

items = [Panel(f"Item {i}", expand=True) for i in range(12)]
console.print(Columns(items))
```

#### Layout (split-pane interfaces)

Build complex split-pane terminal UIs:

```python
from rich.layout import Layout

layout = Layout()
layout.split(
    Layout(name="header", size=3),
    Layout(name="main", ratio=1),
    Layout(name="footer", size=5),
)
layout["main"].split_row(
    Layout(name="sidebar"),
    Layout(name="body", ratio=2, minimum_size=60),
)

layout["header"].update("Header content")
layout["body"].update("Main body")
layout["sidebar"].update("Sidebar")
layout["footer"].update("Footer")

console.print(layout)
```

For a full-screen application with live updates, combine `Layout` with `Live`:

```python
from rich.live import Live

with Live(layout, screen=True, refresh_per_second=10):
    # Update layout regions dynamically
    layout["body"].update("Updated content")
```

### 4.10 Live Display

Update terminal output in place without flickering:

```python
from time import sleep
from rich.live import Live
from rich.table import Table

table = Table()
table.add_column("Row")
table.add_column("Value")

with Live(table, refresh_per_second=4):
    for row in range(12):
        sleep(0.4)
        table.add_row(f"{row}", f"[red]value {row}")
```

`Live` options:

| Parameter | Type | Default | Description |
|---|---|---|---|
| `renderable` | any | *(required)* | The renderable to display |
| `console` | `Console` | `None` | Console instance |
| `screen` | `bool` | `False` | Use full-screen alternate buffer |
| `refresh_per_second` | `float` | `4` | Maximum refresh rate |
| `transient` | `bool` | `False` | Clear display when done |
| `redirect_stdout` | `bool` | `True` | Redirect stdout through Live |
| `redirect_stderr` | `bool` | `True` | Redirect stderr through Live |
| `vertical_overflow` | `str` | `"ellipsis"` | How to handle overflow: `"crop"`, `"ellipsis"`, `"visible"` |

### 4.11 Logging with RichHandler

Replace Python's default logging output with Rich-formatted logs:

```python
import logging
from rich.logging import RichHandler

logging.basicConfig(
    level=logging.DEBUG,
    format="%(message)s",
    datefmt="[%X]",
    handlers=[RichHandler()],
)

log = logging.getLogger("rich")
log.info("Server starting...")
log.warning("Low disk space")
log.error("Connection failed")
log.debug("Received %d bytes", 4096)
```

`RichHandler` options:

| Parameter | Type | Default | Description |
|---|---|---|---|
| `level` | `int` | `NOTSET` | Logging level |
| `console` | `Console` | `None` | Console to write to |
| `show_time` | `bool` | `True` | Show timestamp |
| `show_level` | `bool` | `True` | Show log level |
| `show_path` | `bool` | `True` | Show file path and line number |
| `markup` | `bool` | `False` | Enable Rich markup in log messages |
| `rich_tracebacks` | `bool` | `False` | Use Rich tracebacks for exceptions |
| `tracebacks_show_locals` | `bool` | `False` | Show locals in Rich tracebacks |
| `log_time_format` | `str` | `"[%X]"` | Time format string |

> [!TIP]
> Set `markup=True` on `RichHandler` to use Rich markup in your log messages: `log.info("[bold green]Success![/]")`. Set `rich_tracebacks=True` to get Rich-formatted exception tracebacks in your logs.

#### Console.log()

Rich also provides a standalone log method that adds timestamps and source location:

```python
from rich.console import Console

console = Console()
console.log("Starting process...")
console.log("Result:", {"status": "ok", "count": 42}, log_locals=True)
```

### 4.12 Prompts

Rich provides styled prompts for user input with built-in validation:

```python
from rich.prompt import Prompt, IntPrompt, FloatPrompt, Confirm

# Basic text prompt
name = Prompt.ask("Enter your name")

# With a default value
name = Prompt.ask("Enter your name", default="World")

# Integer input with validation (re-prompts on invalid input)
age = IntPrompt.ask("Enter your age")

# Float input
weight = FloatPrompt.ask("Enter weight in kg")

# Yes/no confirmation
if Confirm.ask("Continue?"):
    print("Proceeding...")

# Prompt with choices (validates input against choices)
color = Prompt.ask("Pick a color", choices=["red", "green", "blue"])
```

### 4.13 Status and Spinners

#### Status spinner

Show a spinner while a long-running task executes:

```python
from rich.console import Console

console = Console()

with console.status("[bold green]Working on tasks...") as status:
    # do work
    import time
    tasks = [f"task {n}" for n in range(1, 6)]
    while tasks:
        task = tasks.pop(0)
        time.sleep(1)
        console.log(f"{task} complete")
```

#### Spinner renderable

Use a spinner as a standalone renderable:

```python
from rich.spinner import Spinner

spinner = Spinner("dots", text="Loading...")
# Use within a Live display or other container
```

Available spinner styles include: `dots`, `line`, `pipe`, `simpleDots`, `simpleDotsScrolling`, `star`, `arc`, `bouncingBall`, `pong`, and many more. See `rich.spinner.SPINNERS` for the full list.

### 4.14 JSON Pretty Printing

#### From the Python API

```python
from rich import print_json

# From a JSON string
print_json('{"name": "Rich", "version": 13}')

# From a Python object
print_json(data={"users": [{"id": 1, "name": "Alice"}]})
```

#### From the Console

```python
from rich.json import JSON

json_display = JSON('{"key": "value", "list": [1, 2, 3]}')
console.print(json_display)
```

#### CLI utility

```bash
# Pretty print a JSON file
python -m rich.json data.json

# From stdin
cat data.json | python -m rich.json -

# With custom indent
python -m rich.json data.json --indent 4
```

### 4.15 Inspect

Examine any Python object interactively:

```python
from rich import inspect

# Basic inspection -- shows attributes and values
inspect([1, 2, 3])

# Show methods
inspect([1, 2, 3], methods=True)

# Show full help text
inspect([1, 2, 3], help=True)

# Show private attributes
inspect([1, 2, 3], private=True)

# Show everything
inspect([1, 2, 3], all=True)
```

`inspect()` is particularly useful in the REPL for exploring unfamiliar objects and APIs.

### 4.16 Exporting Output

Rich can capture and export rendered output to HTML, SVG, or plain text.

```python
from rich.console import Console
from rich.table import Table

# Enable recording
console = Console(record=True)

table = Table(title="Data")
table.add_column("Name")
table.add_column("Value")
table.add_row("Alpha", "100")
table.add_row("Beta", "200")

console.print(table)

# Export methods (return strings)
html = console.export_html()
text = console.export_text()
svg = console.export_svg(title="My Output")

# Save methods (write to files)
console.save_html("output.html", clear=False)
console.save_text("output.txt", clear=False)
console.save_svg("output.svg", title="My Output")
```

> [!IMPORTANT]
> The console output buffer is flushed after each export call by default. Pass `clear=False` to keep the buffer for subsequent exports. If you need multiple export formats from the same output, use `clear=False` on all but the last call.

### 4.17 Themes

#### Defining custom themes

```python
from rich.console import Console
from rich.theme import Theme

theme = Theme({
    "info": "dim cyan",
    "warning": "magenta",
    "danger": "bold red",
    "success": "bold green",
    "highlight": "italic yellow",
})

console = Console(theme=theme)
console.print("[success]Operation completed successfully[/success]")
console.print("[danger]Critical error occurred[/danger]")
```

#### Theme files

Save themes as INI files for reuse:

```ini
# styles.ini
[styles]
info = dim cyan
warning = magenta
danger = bold red
success = bold green
```

```python
from rich.theme import Theme

theme = Theme.read("styles.ini")
```

### 4.18 Custom Renderables

Rich objects implement the "Rich protocol" -- any object can be made renderable by implementing `__rich__()` or `__rich_console__()`:

#### Simple: `__rich__()`

Return any Rich renderable:

```python
from rich.panel import Panel
from rich.text import Text

class Header:
    def __init__(self, title):
        self.title = title

    def __rich__(self):
        return Panel(Text(self.title, justify="center"), style="bold blue")

console.print(Header("My Application"))
```

#### Advanced: `__rich_console__()`

Yield `Segment` objects for complete control:

```python
from rich.console import Console, ConsoleOptions, RenderResult
from rich.segment import Segment
from rich.style import Style

class ColorStripe:
    def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
        for x in range(options.max_width):
            color_index = int(x / options.max_width * 255)
            yield Segment(" ", Style(bgcolor=f"color({color_index})"))
        yield Segment.line()

console.print(ColorStripe())
```

### 4.19 Custom Highlighters

Create highlighters that automatically apply styles based on regex patterns:

```python
from rich.console import Console
from rich.highlighter import RegexHighlighter
from rich.theme import Theme

class EmailHighlighter(RegexHighlighter):
    base_style = "email."
    highlights = [r"(?P<address>[\w.-]+@[\w.-]+\.\w+)"]

theme = Theme({"email.address": "bold magenta"})
console = Console(highlighter=EmailHighlighter(), theme=theme)

console.print("Send mail to [email removed] for more info")
```

The `base_style` is prepended to each named group in the regex. Define the resulting style names in your theme.

---

## 5. Common Tasks

### Recipe 1: Styled error messages

```python
from rich.console import Console
from rich.panel import Panel

console = Console(stderr=True)

def error(message: str) -> None:
    console.print(Panel(f"[bold red]{message}", title="Error", border_style="red"))

error("File not found: config.yaml")
```

### Recipe 2: Progress bar for file downloads

```python
from concurrent.futures import ThreadPoolExecutor
from urllib.request import urlopen
from rich.progress import (
    Progress, BarColumn, DownloadColumn, TransferSpeedColumn, TimeRemainingColumn
)

def download(url: str, path: str, progress, task_id):
    response = urlopen(url)
    size = int(response.info()["Content-length"])
    progress.update(task_id, total=size)
    progress.start_task(task_id)
    with open(path, "wb") as f:
        while chunk := response.read(32768):
            f.write(chunk)
            progress.update(task_id, advance=len(chunk))

progress = Progress(
    "[bold blue]{task.fields[filename]}",
    BarColumn(bar_width=None),
    DownloadColumn(),
    TransferSpeedColumn(),
    TimeRemainingColumn(),
)

urls = ["https://example.com/file1.zip", "https://example.com/file2.zip"]

with progress:
    with ThreadPoolExecutor(max_workers=4) as pool:
        for url in urls:
            filename = url.split("/")[-1]
            task_id = progress.add_task("dl", filename=filename, start=False)
            pool.submit(download, url, filename, progress, task_id)
```

### Recipe 3: Directory listing with columns

```python
import os
from rich import print
from rich.columns import Columns
from rich.text import Text

def list_directory(path: str):
    entries = sorted(os.listdir(path), key=str.lower)
    items = []
    for name in entries:
        full = os.path.join(path, name)
        style = "bold blue" if os.path.isdir(full) else "default"
        text = Text(name, style=style)
        text.highlight_regex(r"\.\w+$", "bold")
        items.append(text)
    print(Columns(items, equal=True, column_first=True))

list_directory(".")
```

### Recipe 4: Full-screen dashboard with Live + Layout

```python
from datetime import datetime
from time import sleep
from rich.console import Console
from rich.layout import Layout
from rich.live import Live
from rich.panel import Panel
from rich.table import Table
from rich.text import Text

layout = Layout()
layout.split(
    Layout(name="header", size=3),
    Layout(name="body", ratio=1),
)

def get_header():
    return Panel(Text(datetime.now().ctime(), justify="center"), style="white on blue")

with Live(layout, screen=True, refresh_per_second=4) as live:
    for i in range(60):
        layout["header"].update(get_header())
        layout["body"].update(Panel(f"Tick: {i}"))
        sleep(1)
```

### Recipe 5: Calendar with colored tables

```python
import calendar
from rich import box
from rich.columns import Columns
from rich.console import Console
from rich.table import Table

def print_month(year: int, month: int):
    cal = calendar.Calendar()
    table = Table(
        title=f"{calendar.month_name[month]} {year}",
        box=box.SIMPLE_HEAVY, style="green", padding=0
    )
    for wd in cal.iterweekdays():
        table.add_column(calendar.day_abbr[wd], justify="right")
    for week in cal.monthdayscalendar(year, month):
        table.add_row(*[str(d) if d else "" for d in week])
    return table

console = Console()
months = [print_month(2026, m) for m in range(1, 13)]
console.print(Columns(months, padding=1, expand=True))
```

### Recipe 6: Enhanced logging for a server

```python
import logging
from rich.logging import RichHandler
from rich.highlighter import RegexHighlighter
from rich.theme import Theme

class RequestHighlighter(RegexHighlighter):
    base_style = "req."
    highlights = [
        r"(?P<method>GET|POST|PUT|DELETE)",
        r"(?P<status>[2]\d{2})",
        r"(?P<error>[45]\d{2})",
        r"(?P<path>/\S+)",
    ]

theme = Theme({
    "req.method": "bold cyan",
    "req.status": "bold green",
    "req.error": "bold red",
    "req.path": "magenta",
})

logging.basicConfig(
    level=logging.INFO,
    format="%(message)s",
    handlers=[RichHandler(console=__import__("rich.console", fromlist=["Console"]).Console(theme=theme))],
)
```

### Recipe 7: Exception handling with Rich tracebacks

```python
from rich.traceback import install
install(show_locals=True, suppress=["click", "flask"])

# All unhandled exceptions now show Rich tracebacks
# with local variables visible and framework frames dimmed
```

### Recipe 8: Nested progress bars

```python
from time import sleep
from rich.console import Group
from rich.live import Live
from rich.panel import Panel
from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn

overall = Progress()
jobs = Progress(SpinnerColumn(), TextColumn("{task.description}"), BarColumn())

group = Group(
    Panel(Group(jobs), title="Current Jobs"),
    overall,
)

overall_task = overall.add_task("Total", total=30)

with Live(group):
    for i in range(3):
        job_task = jobs.add_task(f"Job {i+1}", total=10)
        for j in range(10):
            sleep(0.1)
            jobs.advance(job_task)
            overall.advance(overall_task)
        jobs.update(job_task, visible=False)
```

### Recipe 9: Exporting a table as SVG

```python
from rich.console import Console
from rich.table import Table

console = Console(record=True)

table = Table(title="Data Report")
table.add_column("Metric", style="cyan")
table.add_column("Value", justify="right", style="green")
table.add_row("Users", "1,234")
table.add_row("Revenue", "$56,789")

console.print(table, justify="center")
console.save_svg("report.svg", title="Data Report")
```

### Recipe 10: Pretty-printed class instances

```python
import rich.repr

@rich.repr.auto
class Config:
    def __init__(self, host="localhost", port=8080, debug=False, workers=4):
        self.host = host
        self.port = port
        self.debug = debug
        self.workers = workers

from rich import print
print(Config(debug=True, workers=8))
# Output: Config(host='localhost', port=8080, debug=True, workers=8)
```

### Recipe 11: Rendering Markdown files

```python
from rich.console import Console
from rich.markdown import Markdown

console = Console()

with open("README.md") as f:
    md = Markdown(f.read())

console.print(md)
```

### Recipe 12: Interactive object exploration

```python
from rich import inspect

# Discover what methods a string has
inspect("hello", methods=True)

# Explore a module
import json
inspect(json, methods=True, help=True)
```

---

## 6. Troubleshooting

### Progress bars and Live display not working in Jupyter

**Symptom:** Progress bars or `Live` display produce garbled output or don't update in Jupyter notebooks, particularly with `ipykernel>=7`.

**Cause:** Changes in ipykernel 7+ changed how stdout/stderr are handled, breaking Rich's output detection.

**Workaround:**

```python
from rich.console import Console

# Force Jupyter mode explicitly
console = Console(force_jupyter=True)
```

If that doesn't help, pin to an older ipykernel:

```bash
pip install "ipykernel<7"
```

> [!CAUTION]
> This is a known open issue (#3868). If you encounter it, check the issue for the latest status and workarounds.

### Colors not showing in output

**Symptom:** Output appears as plain text without any colors or styling.

**Check the following:**

1. **Terminal support:** Use a modern terminal (Windows Terminal, iTerm2, GNOME Terminal, etc.). Legacy `cmd.exe` has limited support.

2. **Piped output:** Rich disables color when output is piped to a file or another command. Force it with:

   ```python
   console = Console(force_terminal=True)
   ```

3. **`NO_COLOR` environment variable:** If `NO_COLOR` is set, Rich respects it and disables all color. Unset it if you want color.

4. **`TERM=dumb`:** Rich treats `TERM=dumb` as a no-color terminal. Check your environment.

> [!NOTE]
> Run `python -m rich` to see a test card. If it renders with colors, Rich and your terminal are working correctly. If it renders without colors, the issue is with your terminal configuration.

### Emoji and Unicode characters displaying incorrectly

**Symptom:** Emoji appear as question marks, boxes, or cause misaligned output.

**Solutions:**

- Use a font with good Unicode coverage (e.g., Cascadia Code, JetBrains Mono, Nerd Fonts).
- Set the `UNICODE_VERSION` environment variable to match your terminal's Unicode support:

  ```bash
  export UNICODE_VERSION=13.0.0
  ```

- Disable emoji rendering:

  ```python
  console = Console(emoji=False)
  ```

### Rich markup appearing as literal text

**Symptom:** `[bold]text[/bold]` prints literally instead of rendering as bold.

**Causes:**

- Using Python's built-in `print()` instead of `rich.print()` or `console.print()`.
- Markup disabled on the Console: `Console(markup=False)`.
- Unescaped square brackets in text. Escape literal brackets:

  ```python
  console.print("Use \\[bold] for bold")  # Escaped
  ```

### VSCode Remote SSH traceback links

**Symptom:** When using Rich tracebacks over VSCode Remote SSH, file links in tracebacks point to local filesystem paths instead of the remote server.

**Status:** Known issue (#4036). The file paths in tracebacks reference the remote server's filesystem, but VSCode may not correctly resolve them as remote paths.

### Windows legacy console issues

**Symptom:** Colors look wrong, or stderr output uses stdout's color handle.

**Solutions:**

- Use **Windows Terminal** instead of legacy `cmd.exe` or PowerShell ISE.
- Rich's legacy Windows color layer has a known issue (#4071) where it always uses the stdout handle, even for stderr streams. If you need correct stderr coloring, use Windows Terminal which supports native VT escape sequences.

> [!WARNING]
> The legacy Windows console adapter (`rich._win32_console`) is a compatibility layer for older Windows terminals. It has known limitations. Always prefer Windows Terminal for the best Rich experience on Windows.

### `console.print()` with no arguments

**Symptom:** `console.print()` with no arguments does not behave the same as `print()`.

**Explanation:** Python's built-in `print()` outputs a newline when called with no arguments. `console.print()` also outputs a newline, but if you pass empty `*args` (e.g., `console.print(*[])`), the behavior differs. This is a known edge case (#3701).

---

## 7. FAQ

**Q: Is Rich a CLI framework?**
A: No. Rich is a library for producing beautiful terminal output. It does not handle argument parsing, command routing, or CLI application structure. For a full CLI framework built on Rich, see [Textual](https://github.com/Textualize/textual) (TUI) or use Rich alongside [Click](https://click.palletsprojects.com/) or [Typer](https://typer.tiangolo.com/).

**Q: What are the `python -m rich.*` commands?**
A: Rich includes small convenience utilities for quick terminal use:
- `python -m rich` -- displays a feature demo test card
- `python -m rich.json <file>` -- pretty-prints a JSON file
- `python -m rich.syntax <file>` -- syntax-highlights a source file
- `python -m rich.markdown <file>` -- renders a Markdown file

These are convenience wrappers, not the primary interface. Rich is designed to be used as a Python library.

**Q: How do I disable all Rich formatting?**
A: Several approaches:
- `Console(no_color=True)` -- disables color but keeps layout
- `Console(force_terminal=False)` -- disables terminal features when not a TTY
- Set `NO_COLOR=1` environment variable
- Set `TERM=dumb` environment variable

**Q: Does Rich work in Jupyter notebooks?**
A: Yes. Rich auto-detects Jupyter and renders output as HTML in notebook cells. You can force this behavior with `Console(force_jupyter=True)`. Note that `ipykernel>=7` introduced a compatibility issue with progress bars (#3868).

**Q: How do I use Rich with Python's logging module?**
A: Use `RichHandler`:

```python
import logging
from rich.logging import RichHandler
logging.basicConfig(level=logging.INFO, handlers=[RichHandler()])
```

See [Section 4.11](#411-logging-with-richhandler) for full details.

**Q: Can I export Rich output to HTML or images?**
A: Yes. Create a `Console` with `record=True`, print your content, then use `export_html()`, `export_svg()`, or `export_text()`. See [Section 4.16](#416-exporting-output).

**Q: How do I make my own objects printable with Rich?**
A: Implement `__rich__()` (return a renderable) or `__rich_console__()` (yield Segments) on your class. See [Section 4.18](#418-custom-renderables).

**Q: What color systems does Rich support?**
A: Rich supports 4-bit (16 standard colors), 8-bit (256 colors), and 24-bit truecolor (16.7 million colors). It auto-detects the terminal's capability and converts colors down automatically. You can force a specific system with `Console(color_system="truecolor")`.

**Q: How do I use Rich alongside other libraries that write to the terminal?**
A: If another library writes directly to stdout while Rich is using `Live` or `Progress`, output can become garbled. Use `Live(redirect_stdout=True)` (the default) to capture stdout writes, or use `console.log()` for your own output within a `Live` context.

**Q: What is the performance impact of Rich?**
A: Rich adds negligible overhead for simple print operations. For complex renderables (large tables, progress bars), Rich caches style calculations internally. The test card (`python -m rich`) benchmarks cold-cache and warm-cache render times so you can evaluate performance on your system.

For architecture details, rendering internals, and advanced customization, see the [Admin Guide](/guides/Textualize/rich/admin-guide/).

---

_Generated May 2026 from Textualize/rich at 46cebbb. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
