Textual is a TUI (Text User Interface) framework for Python using Rich as a renderer.

Related tags



Textual is a TUI (Text User Interface) framework for Python using Rich as a renderer.

The end goal is to be able to rapidly create rich terminal applications that look as good as possible (within the restrictions imposed by a terminal emulator).

Rich TUI will integrate tightly with its parent project, Rich. Any of the existing renderables can be used in a more dynamic application.

This project is currently a work in progress and may not be usable for a while. Follow @willmcgugan for progress updates, or post in Discussions if you have any requests / suggestions.


  • Add remaining easing functions

    Add remaining easing functions

    Fixes #81 , does the same work as #86 ; I chose to open the PR either way because the work had already been done.

    opened by RojerGS 18
  • error when running examples

    error when running examples

    i installed textual with pip and i tried to run the first example in the readme with python3 filename.py but i get the error TypeError: on_key() takes 1 positional argument but 2 were given when i press a key. got a similiar error with another example. sorry if im being dumb : p

    opened by itsUrcute 16
  • Add more easing functions

    Add more easing functions

    There are a number of 'easing functions' used by the animation system. At the top of _animator.py you will see the following:

    EASING = {
        "none": lambda x: 1.0,
        "round": lambda x: 0.0 if x < 0.5 else 1.0,
        "linear": lambda x: x,
        "in_cubic": lambda x: x * x * x,
        "in_out_cubic": lambda x: 4 * x * x * x if x < 0.5 else 1 - pow(-2 * x + 2, 3) / 2,
        "out_cubic": lambda x: 1 - pow(1 - x, 3),

    These function have been copied from https://easings.net/ and translated from Javascript to Python. I would like to add the remaining functions to the EASING dict above.

    See the animation.py example as a way of testing the above functions.

    help wanted good first issue 
    opened by willmcgugan 15
  • Horizontal scrolling

    Horizontal scrolling

    (hope you don't mind me opening an issue to ask a question, I've tried hard to get to the bottom of this myself)

    I'm trying to get horizontal scrolling working with textual and a rich table, but no luck

    Below is what I have so far.

    It seems like the table is refusing to exceed the width of the terminal, thus the horizontal scroll bar of ScrollView is not coming into play.

    Vertical scrolling is working great.

    What am I doing wrong?

    (ref: https://twitter.com/samuel_colvin/status/1426289617632960515)

    from rich.table import Table
    from textual import events
    from textual.app import App
    from textual.widgets import Header, Footer, ScrollView
    class MyApp(App):
        """An example of a very simple Textual App"""
        async def on_load(self, event: events.Load) -> None:
            await self.bind("q", "quit", "Quit")
        async def on_mount(self, event: events.Mount) -> None:
            self.body = body = ScrollView()
            body.virtual_size.width = 300
            await self.view.dock(body)
            async def add_content():
                table = Table(title="Demo", width=300, min_width=300)
                for i in range(40):
                    table.add_column(f'Col {i + 1}', style='magenta')
                for i in range(40):
                    table.add_row(*[f'cell {i},{j}' for j in range(40)])
                await body.update(table)
            await self.call_later(add_content)
    MyApp.run(title="Simple App", log="textual.log")


    python 3.9.5
    OS: Ubuntu 21.04 with standard terminal
    opened by samuelcolvin 9
  • Typing error with Reactive

    Typing error with Reactive

    PyCharm gives me typing error with Reactive, see screenshot:


    I'm unsure why this is the case given that mypy doesn't yield such error.

    Side question: now that I have found myself a project to use Textual while fully understanding that this is WIP, I'll likely come across many little things like this one you may already be aware of. Should I keep opening issues? Or should I use some other, less formal avenue to keep the noise low and only open ticket when you request it? I'm thinking of Twitter DMs, or possibly some discord server and/or DM. Let me know what works best for you at this stage.

    opened by abey79 7
  • Remove unreachable code

    Remove unreachable code

    Because there is a return preceding the yield it isn't possible to reach the yield

    opened by sanders41 6
  • asyncio event loop isn't closed on exit

    asyncio event loop isn't closed on exit

    When run with Python 3.8.5 on Ubuntu 20.04 LTS, the event loop isn't closed when the example is quit by pressing q.

    Following error is output and the program exists:

    /usr/lib/python3.8/asyncio/base_events:654: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=False>

    The terminal is then printing raw bytes (?) of the mouse movement anytime you move the cursor over the window.


    I'm not sure if it's the Python version or some difference between Linux and OSX.

    (In order to run the example I had to patch src/textual/_parser.py, because the type hint list[str] isn't supported in 3.8. I just replaced it with list.)

    opened by sinus-x 5
  • Dynamically adding placeholders

    Dynamically adding placeholders

    I was trying to add e.g. a new row to a layout after it was created in on_startup(), but it looks like it has no effect (I tried refresh() and require_layout()). Just asking as I know it might be early for that. Keep up the great work anyway!

    opened by davidbrochart 5
  • Scrolling and hitting Q at the same time in textual.app hung the script entirely

    Scrolling and hitting Q at the same time in textual.app hung the script entirely

    See attached video - if I hit Q while scrolling up and down with the trackpad I've occasionally managed to cause the terminal app to hang - such that it no longer responds to keyboard commands or scrolling, plus hitting Ctrl+C or even Ctrl+Z fails to exit it.

    I recorded a video here with software that shows the keys I'm pressing:


    opened by simonw 5
  • 0.1.9 build failing with Poetry.

    0.1.9 build failing with Poetry.

    Going to admit this is my first time using Poetry so I'm not too familiar with it yet, but it appears to not like the Rich package source that's provided. No idea why. Going to try a manual install, if that fails, I'll try the regular Rich repo and hope nothings broken :)

    $ poetry install
    Installing dependencies from lock file
    Package operations: 1 install, 0 updates, 0 removals
      • Installing rich (10.6.0 8ae1d4a): Failed
      Command '['git', 'clone', '--recurse-submodules', '[email protected]:willmcgugan/rich', '/home/hyoon/.local/share/virtualenvs/textual-4a5vNUb8/src/rich']' returned non-zero exit status 128.
      at ~/.local/lib/python3.6/site-packages/poetry/utils/_compat.py:218 in run
          214│                 raise
          215│             retcode = process.poll()
          216│             if check and retcode:
          217│                 raise CalledProcessError(
        → 218│                     retcode, process.args, output=stdout, stderr=stderr
          219│                 )
          220│         finally:
          221│             # None because our context manager __exit__ does not use them.
          222│             process.__exit__(None, None, None)
    === test session starts ===
    platform linux (ubuntu 18) -- Python 3.7.11, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- /home/hyoon/.local/share/virtualenvs/textual-4a5vNUb8/bin/python
    cachedir: .pytest_cache
    Coverage.py warning: Module textual was never imported. (module-not-imported)
    (because of the build fail)

    Will report back,.

    opened by ethixkr 4
  • Reading from stdin

    Reading from stdin


    I'm trying to make a textual app that deals with data from stdin. However, if I pipe something to a textual app, it gets consumed as keystrokes. When I consume stdin first (via sys.stdin.read(), for example), the app does not process keystrokes (rather, the typed keys get superimposed onto it).

    Is there a solution for this?

    opened by ohle 0
  • Replace set comprehention with `set()`

    Replace set comprehention with `set()`

    The comprehension here is unnecessary

    opened by tusharsadhwani 0
  • Added some information about grid making

    Added some information about grid making


    opened by Shirobachi 0
  • No project description on pypi.org

    No project description on pypi.org

    opened by schneiderfelipe 0
  • Make header symbol configurable

    Make header symbol configurable

    Make it possible to change the symbol shown in the left side of the Header widget.

    Let me know if there are any other changes I can make, I'm happy to help!

    opened by Danmou 0
  • Make footer style configurable

    Make footer style configurable

    Simple change to allow using a different style for the Footer widget.

    opened by Danmou 0
  • Allow binding of the space key

    Allow binding of the space key

    Allow the space key to be bound to the application.

    opened by pvmm 0
  • Added 'title' attribute to Placeholder class

    Added 'title' attribute to Placeholder class

    A new attribute which allows one to change the title of a placeholder independently of the internal name of the window or the class.

    This introduces a feature I felt was lacking, so I implemented it myself.

    Example: await self.view.dock(Placeholder(title='Output'), Placeholder(title='Data'), edge="top")


    The results can be seen in the image above.

    opened by alshapton 0
  • result = App.run()

    result = App.run()

    To be added by @willmcgugan

    1. Thanks for such a great library
    2. We are using your library! See the result here: https://github.com/fluidattacks/makes/pull/725
    3. This is not an outstanding feature that must be added
    4. But It would be very useful in some cases

    The App class is normally used as a whole application: App.run()

    It would be useful if we could return data from it on exit so we can do result = App.run(). This allows for having many 'scenes' (Apps) in our application, for instance for asking user for a value and then do some work, then show other 'scene' (other App), etc

    opened by kamadorueda 2
  • Update README.md to fix link for Grid example

    Update README.md to fix link for Grid example

    The URL for the Grid layout example was pointing to the calculator example. URL has been updated to link to grid.py.

    opened by jpecor 0
  • v0.1.11(Sep 12, 2021)

    [0.1.11] - 2021-09-12


    • Changed message handlers to use prefix handle_
    • Renamed messages to drop the Message suffix
    • Events now bubble by default
    • Refactor of layout


    • Added App.measure
    • Added auto_width to Vertical Layout, WindowView, an ScrollView
    • Added big_table.py example
    • Added easing.py example
    Source code(tar.gz)
    Source code(zip)
  • v0.1.10(Aug 25, 2021)

    [0.1.10] - 2021-08-25


    • Added keyboard control of tree control
    • Added Widget.gutter to calculate space between renderable and outside edge
    • Added margin, padding, and border attributes to Widget


    • Callbacks may be async or non-async.
    • Event handler event argument is optional.
    • Fixed exception in clock example https://github.com/willmcgugan/textual/issues/52
    • Added Message.wait() which waits for a message to be processed
    • Key events are now sent to widgets first, before processing bindings
    Source code(tar.gz)
    Source code(zip)
  • v0.1.3(Jul 5, 2021)

    In this version there is a new more-powerful renderer that supports overlapping regions. There is also a new layout engine which is more intuitive that Rich's Layout clas.

    Source code(tar.gz)
    Source code(zip)
  • v0.1.2(Jun 24, 2021)

Will McGugan
I'm a full-stack software developer, and Python expert. Creator of Rich and @PyFilesystem.
Will McGugan
A cross platform package to do curses-like operations, plus higher level APIs and widgets to create text UIs and ASCII art animations

ASCIIMATICS Asciimatics is a package to help people create full-screen text UIs (from interactive forms to ASCII animations) on any platform. It is li

null 2.8k Oct 23, 2021
Cement is an advanced Application Framework for Python, with a primary focus on CLI

Cement Framework Cement is an advanced Application Framework for Python, with a primary focus on Command Line Interfaces (CLI). Its goal is to introdu

Data Folk Labs, LLC 1k Oct 25, 2021
Python Command-line Application Tools

Clint: Python Command-line Interface Tools Clint is a module filled with a set of awesome tools for developing commandline applications. C ommand L in

Kenneth Reitz Archive 57 Oct 12, 2021
Cleo allows you to create beautiful and testable command-line interfaces.

Cleo Create beautiful and testable command-line interfaces. Cleo is mostly a higher level wrapper for CliKit, so a lot of the components and utilities

Sébastien Eustace 763 Oct 15, 2021
Pythonic command line arguments parser, that will make you smile

docopt creates beautiful command-line interfaces Video introduction to docopt: PyCon UK 2012: Create *beautiful* command-line interfaces with Python N

null 7.5k Oct 25, 2021
Simple cross-platform colored terminal text in Python

Colorama Makes ANSI escape character sequences (for producing colored terminal text and cursor positioning) work under MS Windows. PyPI for releases |

Jonathan Hartley 2.6k Oct 23, 2021
A drop-in replacement for argparse that allows options to also be set via config files and/or environment variables.

ConfigArgParse Overview Applications with more than a handful of user-settable options are best configured through a combination of command line args,

null 544 Oct 18, 2021
Color text streams with a polished command line interface

colout(1) -- Color Up Arbitrary Command Output Synopsis colout [-h] [-r RESOURCE] colout [-g] [-c] [-l min,max] [-a] [-t] [-T DIR] [-P DIR] [-d COLORM

nojhan 1.1k Sep 28, 2021
A fast, stateless http slash commands framework for scale. Built by the Crunchy bot team.

Roid ?? A fast, stateless http slash commands framework for scale. Built by the Crunchy bot team. ?? Installation You can install roid in it's default

Harrison Burt 7 Oct 17, 2021
Python and tab completion, better together.

argcomplete - Bash tab completion for argparse Tab complete all the things! Argcomplete provides easy, extensible command line tab completion of argum

Andrey Kislyuk 991 Oct 22, 2021
Python library that measures the width of unicode strings rendered to a terminal

Introduction This library is mainly for CLI programs that carefully produce output for Terminals, or make pretend to be an emulator. Problem Statement

Jeff Quast 250 Oct 15, 2021
A thin, practical wrapper around terminal capabilities in Python

Blessings Coding with Blessings looks like this... from blessings import Terminal t = Terminal() print(t.bold('Hi there!')) print(t.bold_red_on_brig

Erik Rose 1.3k Oct 19, 2021
Python composable command line interface toolkit

$ click_ Click is a Python package for creating beautiful command line interfaces in a composable way with as little code as necessary. It's the "Comm

The Pallets Projects 11.5k Oct 24, 2021
Typer, build great CLIs. Easy to code. Based on Python type hints.

Typer, build great CLIs. Easy to code. Based on Python type hints. Documentation: https://typer.tiangolo.com Source Code: https://github.com/tiangolo/

Sebastián Ramírez 6.5k Oct 22, 2021
emoji terminal output for Python

Emoji Emoji for Python. This project was inspired by kyokomi. Example The entire set of Emoji codes as defined by the unicode consortium is supported

Taehoon Kim 1.3k Oct 16, 2021
Library for building powerful interactive command line applications in Python

Python Prompt Toolkit prompt_toolkit is a library for building powerful interactive command line applications in Python. Read the documentation on rea

prompt-toolkit 7.3k Oct 23, 2021
Command line animations based on the state of the system

shell-emotions Command line animations based on the state of the system for Linux or Windows 10 The ascii animations were created using a modified ver

Simon Malave 61 Oct 21, 2021
Python Fire is a library for automatically generating command line interfaces (CLIs) from absolutely any Python object.

Python Fire Python Fire is a library for automatically generating command line interfaces (CLIs) from absolutely any Python object. Python Fire is a s

Google 20.3k Oct 24, 2021
sane is a command runner made simple.

sane is a command runner made simple.

Miguel M. 14 Jul 24, 2021