Skip to content

curses

The Python curses module provides an interface to the curses library for building text-based user interfaces in Unix terminals. It controls cursor movement, text rendering, colors, and keyboard input through a grid of character cells, enabling interactive applications that run entirely in the terminal. The module is available on Unix-like systems only.

A minimal application wraps a function with curses.wrapper() to handle initialization and cleanup automatically:

Python hello.py
import curses

def main(stdscr):
    stdscr.addstr(0, 0, "Hello, curses!")
    stdscr.refresh()
    stdscr.getch()

curses.wrapper(main)

Run it in your terminal:

Shell
$ python hello.py

The terminal clears, displays “Hello, curses!”, and waits for a keypress before restoring the normal display.

Key Features

  • Creates and manages rectangular windows and panels within the terminal
  • Supports foreground and background color pairs for styled text output
  • Handles keyboard input including function keys, arrow keys, and special characters
  • Draws borders, lines, and box characters using the alternate character set
  • Provides mouse event support for click and scroll interactions
  • Works portably across Unix-like systems by wrapping the ncurses library
  • Available on Unix-like systems only, not on Windows or WebAssembly platforms

Frequently Used Classes and Functions

Object Type Description
curses.wrapper() Function Initializes curses, calls a function, and restores the terminal on exit
curses.initscr() Function Initializes the library and returns a window covering the entire screen
curses.newwin() Function Creates a new window with specified dimensions and position
curses.start_color() Function Initializes color support and defines the eight basic colors
curses.init_pair() Function Defines a foreground and background color pair by number
curses.color_pair() Function Returns the attribute value for displaying text in a given color pair
window.addstr() Method Paints a string at the current or specified position in a window
window.getch() Method Reads a single character or special key code from the user
window.refresh() Method Updates the physical terminal display to match the window buffer
window.getmaxyx() Method Returns the height and width of the window as a tuple

Examples

Drawing a border and rendering colored text centered on the screen:

Python colored_box.py
import curses

def main(stdscr):
    curses.start_color()
    curses.init_pair(1, curses.COLOR_YELLOW, curses.COLOR_BLUE)
    stdscr.box()
    height, width = stdscr.getmaxyx()
    label = "Hello, curses!"
    stdscr.addstr(
        height // 2,
        width // 2 - len(label) // 2,
        label,
        curses.color_pair(1) | curses.A_BOLD,
    )
    stdscr.refresh()
    stdscr.getch()

curses.wrapper(main)

Reading arrow key input to move a label around the screen:

Python move_text.py
import curses

def main(stdscr):
    stdscr.keypad(True)
    y, x = 5, 5
    label = "Move me!"
    while True:
        stdscr.clear()
        stdscr.addstr(y, x, label)
        stdscr.refresh()
        key = stdscr.getch()
        rows, cols = stdscr.getmaxyx()
        if key == curses.KEY_UP:
            y = max(0, y - 1)
        elif key == curses.KEY_DOWN:
            y = min(rows - 1, y + 1)
        elif key == curses.KEY_LEFT:
            x = max(0, x - 1)
        elif key == curses.KEY_RIGHT:
            x = min(cols - len(label) - 1, x + 1)
        elif key == ord("q"):
            break

curses.wrapper(main)

Common Use Cases

The most common tasks for curses include:

  • Building interactive text menus and navigation systems
  • Creating real-time monitoring dashboards in the terminal
  • Implementing full-screen text editors and file browsers
  • Displaying progress indicators that update in place without scrolling
  • Handling raw keyboard input for game-like or interactive terminal applications

Real-World Example

A live dashboard uses separate subwindows for a fixed header and a scrolling log area. The header stays pinned while the body accumulates status lines on each tick:

Python dashboard.py
import curses
import time

def main(stdscr):
    curses.start_color()
    curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
    curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK)
    curses.curs_set(0)

    height, width = stdscr.getmaxyx()
    header = stdscr.subwin(3, width, 0, 0)
    body = stdscr.subwin(height - 3, width, 3, 0)

    messages = []
    for tick in range(10):
        header.erase()
        header.bkgd(" ", curses.color_pair(1))
        title = f"Dashboard  |  Tick: {tick}"
        header.addstr(1, 2, title, curses.color_pair(1) | curses.A_BOLD)
        header.refresh()

        messages.append(f"[{tick:02d}] System OK")
        body.erase()
        body.box()
        for i, msg in enumerate(messages[-(height - 5):]):
            body.addstr(i + 1, 2, msg, curses.color_pair(2))
        body.refresh()

        time.sleep(1)

    stdscr.getch()

curses.wrapper(main)

Run it in your terminal:

Shell
$ python dashboard.py

The header updates on each tick while the body accumulates log lines, demonstrating how curses composites independent windows into a single cohesive display.

Tutorial

Python Textual: Build Beautiful UIs in the Terminal

Textual is a Python library for building text-based user interfaces (TUIs) that support rich text, advanced layouts, and event-driven interactivity in the terminal. This tutorial showcases some of the ways you can design an appealing and engaging UI using Textual.

intermediate front-end tools

For additional information on related topics, take a look at the following resources:


By Leodanis Pozo Ramos • Updated March 25, 2026