Textual is a TUI (Text User Interface) framework for Python inspired by modern web development.

Overview

Textual

screenshot

Textual is a TUI (Text User Interface) framework for Python inspired by modern web development. Currently a work in progress, but usable by brave souls who don't mind some API instability between updates.

Textual currently runs on MacOS / Linux only. Windows support is in the pipeline.

Follow @willmcgugan for progress updates, or post in Discussions if you have any requests / suggestions.

How it works

Textual uses Rich to render rich text, so anything that Rich can render may be used in Textual.

Event handling in Textual is asynchronous (using async and await keywords). Widgets (UI components) can independently update and communicate with each other via message passing.

Textual has more in common with modern web development than it does with curses; layout is done with CSS grid and (soon) the theme may be customized with CSS. Other techniques are borrowed from JS frameworks such as Vue and Reactive.

Installation

You can install Textual via pip (pip install textual), or by checking out the repo and installing with poetry.

poetry install

Once installed you can run the following command for a quick test, or see examples (below):

python -m textual.app

Textual requires Python 3.7 or above.

Examples

Until I've written the documentation, the examples may be the best way to learn Textual.

You can see some of these examples in action in the Developer Video Log.

  • animation.py Demonstration of 60fps animation easing function
  • calculator.py A "clone" of the MacOS calculator using Grid layout
  • code_viewer.py A demonstration of a tree view which loads syntax highlighted code
  • grid.py A simple demonstration of adding widgets in a Grid layout
  • grid_auto.py A demonstration of automatic Grid layout
  • simple.py A very simple Textual app with scrolling Markdown view

Building Textual applications

This guide is a work in progress

Let's look at the simplest Textual app which does something:

from textual.app import App


class Beeper(App):
    async def on_key(self, event):
        self.console.bell()


Beeper.run()

Here we can see a textual app with a single on_key method which will receive key events. Any key event will result in playing the terminal bell (which will generally emit an irritating beep). Hit Ctrl+C to exit.

Event handlers in Textual are defined by convention, not by inheritance (so you won't find an on_key method in the base class). Each event has a name attribute which for the key event is simply "key". Textual will call the method named on_ if it exists.

Let's look at a slightly more interesting example:

from textual.app import App


class ColorChanger(App):
    async def on_key(self, event):
        if event.key.isdigit():
            self.background = f"on color({event.key})"


ColorChanger.run(log="textual.log")

This example also handles key events, and will set App.background if the key is a digit. So pressing the keys 0 to 9 will change the background color to the corresponding ansi color.

Note that we didn't need to explicitly refresh the screen or draw anything. Setting the background attribute to a Rich style is enough for Textual to update the visuals. This is an example of reactivity in Textual. To make changes to the terminal interface you modify the state and let Textual update the UI.

Widgets

To make more interesting apps you will need to make use of widgets, which are independent user interface elements. Textual comes with a (growing) library of widgets, but you can develop your own.

Let's look at an app which contains widgets. We will be using the built in Placeholder widget which you can use to design application layouts before you implement the real content.

from textual import events
from textual.app import App
from textual.widgets import Placeholder


class SimpleApp(App):

    async def on_mount(self, event: events.Mount) -> None:
        await self.view.dock(Placeholder(), edge="left", size=40)
        await self.view.dock(Placeholder(), Placeholder(), edge="top")


SimpleApp.run(log="textual.log")

This app contains a single event handler on_mount. The mount event is sent when the app or widget is ready to start processing events, and is typically used for initialization. In this case we are going to call self.view.dock to add widgets to the interface.

Here's the first line in the mount handler:

await self.view.dock(Placeholder(), edge="left", size=40)

Note this method is asynchronous like almost all API methods in Textual. We are awaiting self.view.dock which takes a newly constructed Placeholder widget, and docks it on to the "left" edge of the terminal with a size of 40 characters. In a real app you might use this to display a side-bar.

The following line is similar:

await self.view.dock(Placeholder(), Placeholder(), edge="top")

You will notice that this time we are docking two Placeholder objects onto the "top" edge. We haven't set an explicit size this time so Textual will divide the remaining size amongst the two new widgets.

The last line calls the run class method in the usual way, but with an argument we haven't seen before: log="textual.log" tells Textual to write log information to the given file. You can tail textual.log to see events being processed and other debug information.

If you run the above example, you will see something like the following:

widgets

If you move the mouse over the terminal you will notice that widgets receive mouse events. You can click any of the placeholders to give it input focus.

The dock layout feature is very flexible, but for more sophisticated layouts we can use the grid API. See the calculator.py example which makes use of Grid.

Creating Widgets

You can create your own widgets by subclassing the textual.widget.Widget class and implementing a render() method which should return anything that can be rendered with Rich, including a plain string which will be interpreted as console markup.

Let's look at an example with a custom widget:

None: self.mouse_over = True async def on_leave(self, event: events.Leave) -> None: self.mouse_over = False class HoverApp(App): """Hover widget demonstration.""" async def on_mount(self, event: events.Mount) -> None: hovers = (Hover() for _ in range(10)) await self.view.dock(*hovers, edge="top") HoverApp.run(log="textual.log") ">
from rich.panel import Panel

from textual import events
from textual.app import App
from textual.reactive import Reactive
from textual.widget import Widget


class Hover(Widget):

    mouse_over: Reactive[bool] = Reactive(False)

    def render(self) -> Panel:
        return Panel("Hello [b]World[/b]", style=("on red" if self.mouse_over else ""))

    async def on_enter(self, event: events.Enter) -> None:
        self.mouse_over = True

    async def on_leave(self, event: events.Leave) -> None:
        self.mouse_over = False


class HoverApp(App):
    """Hover widget demonstration."""

    async def on_mount(self, event: events.Mount) -> None:
        hovers = (Hover() for _ in range(10))
        await self.view.dock(*hovers, edge="top")


HoverApp.run(log="textual.log")

The Hover class is a custom widget which displays a panel containing the classic text "Hello World". The first line in the Hover class may seem a little mysterious at this point:

mouse_over: Reactive[bool] = Reactive(False)

This adds a mouse_over attribute to your class which is a bool with a default of False. The typing part (Reactive[bool]) is not required, but will help you find bugs if you are using a tool like Mypy. Adding attributes like this makes them reactive, and any changes will result in the widget updating.

The following render() method is where you define how the widget should be displayed. In the Hover widget we return a Panel containing rich text with a background that changes depending on the value of mouse_over. The goal here is to add a mouse hover effect to the widget, which we can achieve by handling two events: Enter and Leave. These events are sent when the mouse enters or leaves the widget.

Here are the two event handlers again:

    async def on_enter(self, event: events.Enter) -> None:
        self.mouse_over = True

    async def on_leave(self, event: events.Leave) -> None:
        self.mouse_over = False

Both event handlers set the mouse_over attribute which, because it is reactive, will result in the widget's render() method being called.

The app class has a Mount handler where we dock 10 of these custom widgets from the top edge, stacking them vertically. If you run this script you will see something like the following:

widgets

If you move your mouse over the terminal you should see that the widget under the mouse cursor changes to a red background.

Actions and key bindings

Actions in Textual are white-listed functions that may be bound to keys. Let's look at a trivial example of binding a key to an action. Here is an app which exits when we hit the Q key:

from textual.app import App


class Quitter(App):
    async def on_load(self, event):
        await self.bind("q", "quit")


Quitter.run()

If you run this you will get a blank terminal which will return to the prompt when you press Q.

Binding is done in the Load event handler. The bind method takes the key (in this case "q") and binds it to an action ("quit"). The quit action is built in to Textual and simply exits the app.

To define your own actions, add a method that begins with action_, which may take parameters. Let's create a simple action that changes the color of the terminal and binds keys to it:

None: self.background = f"on {color}" Colorizer.run() ">
from textual.app import App


class Colorizer(App):

    async def on_load(self, event):
        await self.bind("r", "color('red')")
        await self.bind("g", "color('green')")
        await self.bind("b", "color('blue')")

    async def action_color(self, color:str) -> None:
        self.background = f"on {color}"


Colorizer.run()

If you run this app you can hit the keys R, G, or B to change the color of the background.

In the on_load method we have bound the keys R, G, and B to the color action with a single parameter. When you press any of these three keys Textual will call the method action_color with the appropriate parameter.

You could be forgiven for thinking that "color('red')" is Python code which Textual evaluates. This is not the case. The action strings are parsed and may not include expressions or arbitrary code. The reason that strings are used over a callable is that (in a future update) key bindings may be loaded from a configuration file.

More on Events

TODO

Watchers

TODO

Animation

TODO

Timers and Intervals

Textual has a set_timer and a set_interval method which work much like their Javascript counterparts. The set_timer method will invoke a callable after a given period of time, and set_interval will invoke a callable repeatedly. Unlike Javascript, these methods expect the time to be in seconds, not milliseconds.

Let's create a simple terminal based clock with the set_interval method:

from datetime import datetime

from rich.align import Align

from textual.app import App
from textual.widget import Widget


class Clock(Widget):
    async def on_mount(self, event):
        self.set_interval(1, callback=self.refresh)

    def render(self) -> Align:
        time = datetime.now().strftime("%X")
        return Align.center(time, vertical="middle")

class ClockApp(App):
    async def on_mount(self, event):
        await self.view.dock(Clock())


ClockApp.run()

If you run this app you will see the current time in the center of the terminal until you hit Ctrl+C.

The Clock widget displays the time using rich.align.Align to position it in the center. In the clock's Mount handler there is the following call to set_interval:

self.set_interval(1, callback=self.refresh)

This tells Textual to call a function (in this case self.refresh which updates the widget) once a second. When a widget is refreshed it calls Clock.render again to display the latest time.

Developer Video Log

Since Textual is a visual medium, I'll be documenting new features and milestones here.

Update 1 - Basic scrolling

Textual update 1

Update 2 - Keyboard toggle

Textual update 2

Update 3 - New scrollbars and smooth scrolling

Textual update 3

Update 4 - Animation system with easing function

Now with a system to animate changes to values, going from the initial to the final value in small increments over time . Here applied to the scroll position. The animation system supports CSS like easing functions. You may be able to tell from the video that the page up / down keys cause the window to first speed up and then slow down.

Textual update 4

Update 5 - New Layout system

A new update system allows for overlapping layers. Animation is now synchronized with the display which makes it very smooth!

Textual update 5

Update 6 - New Layout API

New version (0.1.4) with API updates and the new layout system.

Textual update 6

Update 7 - New Grid Layout

11 July 2021

Added a new layout system modelled on CSS grid. The example demonstrates how once created a grid will adapt to the available space.

Textual update 7

Update 8 - Tree control and scroll views

6 Aug 2021

Added a tree control and refactored the renderer to allow for widgets within a scrollable view

Textual update 8

Comments
  • Implement Windows Driver

    Implement Windows Driver

    Trying to run the textual.app example on Windows 10 with Python 3.9.5:

    ➜ python -m textual.app
    Traceback (most recent call last):
     File "C:\Program Files\Python39\lib\runpy.py", line 197, in _run_module_as_main
       return _run_code(code, main_globals, None,
     File "C:\Program Files\Python39\lib\runpy.py", line 87, in _run_code
       exec(code, run_globals)
     File "C:\CodeProjects\Python\Manim\manimvenv\lib\site-packages\textual\app.py", line 19, in <module>
       from .driver import Driver
     File "C:\CodeProjects\Python\Manim\manimvenv\lib\site-packages\textual\driver.py", line 8, in <module>
       import curses
     File "C:\Program Files\Python39\lib\curses\__init__.py", line 13, in <module>
       from _curses import *
    ModuleNotFoundError: No module named '_curses'
    
    Task 
    opened by kilacoda-old 29
  • As of 0.6.0, bindings on (at least) `left`, `right`, `up` and `down` no longer appear to work

    As of 0.6.0, bindings on (at least) `left`, `right`, `up` and `down` no longer appear to work

    With Textual 0.5.0 I had bindings on the arrow keys that worked fine. Having upgraded to 0.6.0 those bindings no longer seem to work. Isolating the issue I can recreate with this code (some other keys thrown in as control tests)

    from textual.app import App, ComposeResult
    from textual.widgets import TextLog, Header, Footer
    from textual.binding import Binding
    from textual.events import Key
    
    class Binder( App[ None ] ):
    
        CSS = """
        TextLog {
            background: #222200;
            color: #BBBB00;
            text-style: bold;
        }
        """
    
        BINDINGS = [
            Binding( "up",    "log( 'up' )", "Up" ),
            Binding( "down",  "log( 'down' )", "Down" ),
            Binding( "left",  "log( 'left' )", "Left" ),
            Binding( "right", "log( 'right' )", "Right" ),
            Binding( "a", "log( 'a' )", "a" ),
            Binding( "s", "log( 's' )", "s" ),
            Binding( "d", "log( 'd' )", "d" ),
            Binding( "f", "log( 'f' )", "f" ),
            Binding( "left_square_bracket", "log( '[' )", "[" ),
            Binding( "right_square_bracket", "log( ']' )", "]" ),
        ]
    
        def compose( self ) -> ComposeResult:
            yield Header()
            yield TextLog()
            yield Footer()
    
        def on_mount( self ) -> None:
            self.query_one( TextLog ).write( "Ready..." )
            self.query_one( TextLog ).write( "Key bindings being looked for:" )
            self.query_one( TextLog ).write( ", ".join(
                [ binding.key for binding in self.BINDINGS ]
            ) )
    
        def action_log( self, name: str ) -> None:
            self.query_one( TextLog ).write( f"Via binding: {name}" )
    
        def on_key( self, event: Key ) -> None:
            self.query_one( TextLog ).write( f"Via event: {event!r}" )
    
    if __name__ == "__main__":
        Binder().run()
    

    Running the above, pressing the arrow keys vs some of the other keys...

    Screenshot 2022-12-12 at 11 25 12

    bug 
    opened by davep 21
  • Method to run code in a thread

    Method to run code in a thread

    I'd like to add a convenient method to execute in job in a thread.

    It would probably be added to message pump (used by app / widgets).

    It should allow a method to be called with arbitrary parameters, and should return an awaitable.

    await self.call_threaded(my_code, "foo", "bar")
    

    I can see this being used for jobs such as reading from disk (which at the moment blocks the vent loop).

    Some considerations: a thread pool may be appropriate. We don't want this to be unbounded and potentially launch an unlimited number of threads. It should probably work with both async and sync functions, which will require a little inspection. If you want to tackle this, please discuss your ideas here first.

    help wanted level:moderate 
    opened by willmcgugan 16
  • 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
  • [colors] Add a

    [colors] Add a "auto" color

    When text has color: auto [percentage] it will be displayed with the contrasting colour of its background

    As a result we can have widgets that have color: auto; in their CSS, and see their text colour automatically adapted to their background: Screenshot from 2022-06-29 14-33-56

    opened by olivierphi 14
  • feat: initial datatable reactive values

    feat: initial datatable reactive values

    For #1164, adds the six reactive attributes listed in the docs for DataTable to __init__. I noticed the class has three more reactive attributes (cursor_type, cursor_cell, and hover_cell) that aren't listed, but I left those out. Let me know if any of them should also be included.

    opened by aaronst 13
  • Unclosed event loop with easing example

    Unclosed event loop with easing example

    Every time I close the easing example. I get the following error:

    /usr/lib/python3.9/asyncio/base_events.py:681: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=False>
      _warn(f"unclosed event loop {self!r}", ResourceWarning, source=self)
    ResourceWarning: Enable tracemalloc to get the object allocation traceback
    

    I am thinking there are still messages processing at shutdown that are keeping the loop running, but I have not been able to track down the root cause yet.

    Possibly a similar issue to #82?

    OS: Manjaro Linux 21.1.4

    bug 
    opened by sanders41 13
  • Live console widget

    Live console widget

    It would be nice to have a widget that behaves like a console. At first, just able to print and auto-scroll, and scroll bar, with auto-refresh. console.print("another brick in the wall")

    Maybe reuse Rich's Live View / Console?

    opened by hajdbo 13
  • Wrong CSS styles being applied on hover

    Wrong CSS styles being applied on hover

    I noticed this when adding semantic style variants for Button.

    When I hover over the warning button, the border is being set to tall $primary-lighten-3. I would expect it to be set to tall $warning-lighten-3 given Button.-warning has higher specificity.

    Relevant CSS

        Button {
            border: tall $primary-lighten-3;
        }
        Button.-warning {
            background: $warning;
            color: $text-warning;
            border: tall $warning-lighten-3;  
        }
        
        Button.-warning :hover {
            background: $warning-darken-1;
            color: $text-warning-darken-1; 
        }
    
    bug 
    opened by darrenburns 12
  • Tabbed Widget

    Tabbed Widget

    What?

    This PR adds a widget that enables the user to define multiple views as so called tabs and receive a automagically generated bar of tab handles to switch between said views.

    🖼 Some Pictures

    The example code introduced in this PR produces the following: Screenshot 2021-08-11 at 19 09 04 Screenshot 2021-08-11 at 19 09 08 Screenshot 2021-08-11 at 19 09 11

    Some additional info

    • All 4 modes a tab handle can be in are "user-stylable". Those being default, hover, selected, and hover+selected.
    • The type of view a tab uses can be given by the user upon tab creation. Though this is not strictly necessary thanks to DockView.dock_grid().
    opened by timfi 12
  • Mouse click and scroll event support for git-bash/mintty on Windows

    Mouse click and scroll event support for git-bash/mintty on Windows

    The demo looks correct in git-bash on Windows, however it does not respond to mouse movement, click, and scroll events. It would be helpful to extend the existing drivers or driver selection to take this scenario into account. While the platform check will show "Windows", git-bash supports the event types in the Linux driver instead.

    0;70;13M #left mouse button down 0;70;13m #left mouse button up

    It's possible that a more nuanced environment check and loading the Linux driver in that case may enable it to work as expected.

    opened by ariker 1
  • add a

    add a "thin" horiz scrollbar

    First, a screenshot:

    Screen Shot 2022-12-31 at 21 12 24

    I don't like the horizontal scrollbar; even at "size" 1 it is still too fat. So I added an option for a "thin" version, refactoring ScrollBarRender along the way.

    I didn't presume to know how you'd like the CSS to behave, so I went for the simplest I could think of: add a new "scrollbar-thin" boolean style. I am not married to the css design around it, I really only want the "thin" version.

    There's no need to do anything special for a "thin" vertical scrollbar: imo it looks very nice at width 1.

    opened by nitzan-shaked 3
  • WIP: Colors: Add ansi_default and make ansi_* colors actually output their ansi sequences

    WIP: Colors: Add ansi_default and make ansi_* colors actually output their ansi sequences

    Please review the following checklist.

    • [X] Docstrings on all new or modified functions / classes
    • [X] Updated documentation
    • [X] Updated CHANGELOG.md (where appropriate)

    This is marked as WIP because I haven't tested this yet.

    opened by earboxer 3
  • MouseScrollUp/MouseScrollDown => plain MousEvent's

    MouseScrollUp/MouseScrollDown => plain MousEvent's

    ... which means they get passesd x, y, etc. In particular, they are passed the keyboard modifiers. This allows widgets to use e.g. ctrl-wheel to scroll right/left.

    opened by nitzan-shaked 0
  • basic typing fixes

    basic typing fixes

    Hello there. I've run in a small number of typing issues in Textual during my everyday use, and thought I'd attempt a fix in Textual itself.

    My ambitious goal is to run mypy --strict on all the codebase with zero warnings, and I'm about 50% of the way though. However that would be a non-small PR, so I thought I'd start with some obvious issues that should be easy to accept hopefully.

    I've included here a fairly small number of changes, all of which I consider "obvious fixes" in the sense that they either expose actual bugs that exist now, or they break Python contracts, which are bugs waiting to happen.

    I am going to annotate this PR with my reasoning below in a few minutes.

    I hope this is useful. Cheers.

    opened by nitzan-shaked 0
Releases(v0.9.1)
  • v0.9.1(Dec 30, 2022)

    Only Python 3.11 has a high resolution sleep by default. This adds a more accurate sleep for windows on Python < 3.11

    [0.9.1] - 2022-12-30

    Added

    • Added textual._win_sleep for Python on Windows < 3.11 https://github.com/Textualize/textual/pull/1457
    Source code(tar.gz)
    Source code(zip)
  • v0.9.0(Dec 30, 2022)

    No new functionality so speak of, but performance has improved over the 0.8.x version. A change to how rendered content is stored has made updates faster.

    There is also a fix for slow updates on Windows. See this blog post for details.

    This is likely the last release of the year, so I would like to share this music video which seems strangely appropriate.

    https://www.youtube.com/watch?v=kAFxLXqP8UM&ab_channel=Nightwish

    [0.9.0] - 2022-12-30

    Added

    • Added textual.strip.Strip primitive
    • Added textual._cache.FIFOCache
    • Added an option to clear columns in DataTable.clear() https://github.com/Textualize/textual/pull/1427

    Changed

    • Widget.render_line now returns a Strip
    • Fix for slow updates on Windows
    • Bumped Rich dependency
    Source code(tar.gz)
    Source code(zip)
  • v0.8.2(Dec 28, 2022)

  • v0.8.1(Dec 25, 2022)

    I really should be pealing potatoes.

    [0.8.1] - 2022-12-25

    Fixed

    • Fix for overflowing tree issue https://github.com/Textualize/textual/issues/1425
    Source code(tar.gz)
    Source code(zip)
  • v0.8.0(Dec 22, 2022)

    Version 0.8.0 adds a new textual keys command which you can use to preview key events.

    There are a few minor breaking changes in this release. See below for details.

    Screenshot 2022-12-22 at 13 08 11

    [0.8.0] - 2022-12-22

    Fixed

    • Fixed issues with nested auto dimensions https://github.com/Textualize/textual/issues/1402
    • Fixed watch method incorrectly running on first set when value hasn't changed and init=False https://github.com/Textualize/textual/pull/1367
    • App.dark can now be set from App.on_load without an error being raised https://github.com/Textualize/textual/issues/1369
    • Fixed setting visibility changes needing a refresh https://github.com/Textualize/textual/issues/1355

    Added

    • Added textual.actions.SkipAction exception which can be raised from an action to allow parents to process bindings.
    • Added textual keys preview.
    • Added ability to bind to a character in addition to key name. i.e. you can bind to "." or "full_stop".
    • Added TextLog.shrink attribute to allow renderable to reduce in size to fit width.

    Changed

    • Deprecated PRIORITY_BINDINGS class variable.
    • Renamed char to character on Key event.
    • Renamed key_name to name on Key event.
    • Queries/walk_children no longer includes self in results by default https://github.com/Textualize/textual/pull/1416
    Source code(tar.gz)
    Source code(zip)
  • v0.7.0(Dec 17, 2022)

    Mostly fixes in this release.

    [0.7.0] - 2022-12-17

    Added

    • Added PRIORITY_BINDINGS class variable, which can be used to control if a widget's bindings have priority by default. https://github.com/Textualize/textual/issues/1343

    Changed

    • Renamed the Binding argument universal to priority. https://github.com/Textualize/textual/issues/1343
    • When looking for bindings that have priority, they are now looked from App downwards. https://github.com/Textualize/textual/issues/1343
    • BINDINGS on an App-derived class have priority by default. https://github.com/Textualize/textual/issues/1343
    • BINDINGS on a Screen-derived class have priority by default. https://github.com/Textualize/textual/issues/1343
    • Added a message parameter to Widget.exit

    Fixed

    • Fixed validator not running on first reactive set https://github.com/Textualize/textual/pull/1359
    • Ensure only printable characters are used as key_display https://github.com/Textualize/textual/pull/1361
    Source code(tar.gz)
    Source code(zip)
  • v0.6.0(Dec 11, 2022)

    See the blog post for the low down on this release.

    [0.6.0] - 2022-12-11

    Added

    • Added "inherited bindings" -- BINDINGS classvar will be merged with base classes, unless inherit_bindings is set to False
    • Added Tree widget which replaces TreeControl.
    • Added widget Placeholder https://github.com/Textualize/textual/issues/1200.

    Changed

    • Rebuilt DirectoryTree with new Tree control.
    • Empty containers with a dimension set to "auto" will now collapse instead of filling up the available space.
    • Container widgets now have default height of 1fr.
    • The default width of a Label is now auto.

    Fixed

    • Type selectors can now contain numbers https://github.com/Textualize/textual/issues/1253
    • Fixed visibility not affecting children https://github.com/Textualize/textual/issues/1313
    • Fixed issue with auto width/height and relative children https://github.com/Textualize/textual/issues/1319
    • Fixed issue with offset applied to containers https://github.com/Textualize/textual/issues/1256
    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(Nov 20, 2022)

    [0.5.0] - 2022-11-20

    Added

    • Add get_child_by_id and get_widget_by_id, remove get_child https://github.com/Textualize/textual/pull/1146
    • Add easing parameter to Widget.scroll_* methods https://github.com/Textualize/textual/pull/1144
    • Added Widget.call_later which invokes a callback on idle.
    • DOMNode.ancestors no longer includes self.
    • Added DOMNode.ancestors_with_self, which retains the old behaviour of DOMNode.ancestors.
    • Improved the speed of DOMQuery.remove.
    • Added DataTable.clear
    • Added low-level textual.walk methods.
    • It is now possible to await a Widget.remove. https://github.com/Textualize/textual/issues/1094
    • It is now possible to await a DOMQuery.remove. Note that this changes the return value of DOMQuery.remove, which used to return self. https://github.com/Textualize/textual/issues/1094
    • Added Pilot.wait_for_animation
    • Added Widget.move_child https://github.com/Textualize/textual/issues/1121
    • Added a Label widget https://github.com/Textualize/textual/issues/1190
    • Support lazy-instantiated Screens (callables in App.SCREENS) https://github.com/Textualize/textual/pull/1185
    • Display of keys in footer has more sensible defaults https://github.com/Textualize/textual/pull/1213
    • Add App.get_key_display, allowing custom key_display App-wide https://github.com/Textualize/textual/pull/1213

    Changed

    • Watchers are now called immediately when setting the attribute if they are synchronous. https://github.com/Textualize/textual/pull/1145
    • Widget.call_later has been renamed to Widget.call_after_refresh.
    • Button variant values are now checked at runtime. https://github.com/Textualize/textual/issues/1189
    • Added caching of some properties in Styles object

    Fixed

    • Fixed DataTable row not updating after add https://github.com/Textualize/textual/issues/1026
    • Fixed issues with animation. Now objects of different types may be animated.
    • Fixed containers with transparent background not showing borders https://github.com/Textualize/textual/issues/1175
    • Fixed auto-width in horizontal containers https://github.com/Textualize/textual/pull/1155
    • Fixed Input cursor invisible when placeholder empty https://github.com/Textualize/textual/pull/1202
    • Fixed deadlock when removing widgets from the App https://github.com/Textualize/textual/pull/1219
    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Nov 8, 2022)

    Read the blog post: https://textual.textualize.io/blog/2022/11/08/version-040/#version-040

    [0.4.0] - 2022-11-08

    Changed

    • Dropped support for mounting "named" and "anonymous" widgets via App.mount and Widget.mount. Both methods now simply take one or more widgets as positional arguments.
    • DOMNode.query_one now raises a TooManyMatches exception if there is more than one matching node. https://github.com/Textualize/textual/issues/1096
    • App.mount and Widget.mount have new before and after parameters https://github.com/Textualize/textual/issues/778

    Added

    • Added init param to reactive.watch
    • CSS_PATH can now be a list of CSS files https://github.com/Textualize/textual/pull/1079
    • Added DOMQuery.only_one https://github.com/Textualize/textual/issues/1096
    • Writes to stdout are now done in a thread, for smoother animation. https://github.com/Textualize/textual/pull/1104
    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Oct 31, 2022)

    A number of fixes, and internal enhancements.

    We have a new API for running textual apps asynchronously, and a much better way of running integration tests. Testing is important and we will be documenting this in a future release.

    Also in this release, we've made fr units more useful. These CSS units can be used to easily create flexible layouts. See the video below:

    https://user-images.githubusercontent.com/554369/199053126-e16c7047-11ae-4f97-95e7-ca264247184a.mov

    Here's the full changelog

    [0.3.0] - 2022-10-31

    Fixed

    • Fixed issue where scrollbars weren't being unmounted
    • Fixed fr units for horizontal and vertical layouts https://github.com/Textualize/textual/pull/1067
    • Fixed textual run breaking sys.argv https://github.com/Textualize/textual/issues/1064
    • Fixed footer not updating styles when toggling dark mode
    • Fixed how the app title in a Header is centred https://github.com/Textualize/textual/issues/1060
    • Fixed the swapping of button variants https://github.com/Textualize/textual/issues/1048
    • Fixed reserved characters in screenshots https://github.com/Textualize/textual/issues/993
    • Fixed issue with TextLog max_lines https://github.com/Textualize/textual/issues/1058

    Changed

    • DOMQuery now raises InvalidQueryFormat in response to invalid query strings, rather than cryptic CSS error
    • Dropped quit_after, screenshot, and screenshot_title from App.run, which can all be done via auto_pilot
    • Widgets are now closed in reversed DOM order
    • Input widget justify hardcoded to left to prevent text-align interference
    • Changed textual run so that it patches argv in more situations
    • DOM classes and IDs are now always treated fully case-sensitive https://github.com/Textualize/textual/issues/1047

    Added

    • Added Unmount event
    • Added App.run_async method
    • Added App.run_test context manager
    • Added auto_pilot to App.run and App.run_async
    • Added Widget._get_virtual_dom to get scrollbars
    • Added size parameter to run and run_async
    • Added always_update to reactive
    • Returned an awaitable from push_screen, switch_screen, and install_screen https://github.com/Textualize/textual/pull/1061
    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Oct 22, 2022)

  • v0.2.0(Oct 22, 2022)

    This is a merge of the CSS branch with a whole load of amazing features. Hope you enjoy.

    We are now returning to regular releases and working in the open. Thanks for being patient.

    What's Changed

    • Outline by @willmcgugan in https://github.com/Textualize/textual/pull/195
    • Hover pseudo class by @willmcgugan in https://github.com/Textualize/textual/pull/201
    • Rename visible property to display, add setter by @darrenburns in https://github.com/Textualize/textual/pull/213
    • Visibility by @darrenburns in https://github.com/Textualize/textual/pull/212
    • Splitting out parsing of durations into new token types, avoiding Scalar by @darrenburns in https://github.com/Textualize/textual/pull/214
    • Invisible widgets now dont render by @darrenburns in https://github.com/Textualize/textual/pull/219
    • Use the layout as specified in CSS by @darrenburns in https://github.com/Textualize/textual/pull/225
    • Margin spacing is now invisible by @darrenburns in https://github.com/Textualize/textual/pull/221
    • Docstrings for styling properties by @darrenburns in https://github.com/Textualize/textual/pull/222
    • Underline bar renderable by @darrenburns in https://github.com/Textualize/textual/pull/246
    • Allow user to supply loop to App.run, ensure it closes by @darrenburns in https://github.com/Textualize/textual/pull/236
    • Tokenise CSS variables by @darrenburns in https://github.com/Textualize/textual/pull/250
    • Vertical layout by @darrenburns in https://github.com/Textualize/textual/pull/234
    • Horizontal layout by @darrenburns in https://github.com/Textualize/textual/pull/235
    • Variable support in CSS by @darrenburns in https://github.com/Textualize/textual/pull/258
    • Sparklines by @darrenburns in https://github.com/Textualize/textual/pull/269
    • Inline styles view by @willmcgugan in https://github.com/Textualize/textual/pull/254
    • Render opacity by @darrenburns in https://github.com/Textualize/textual/pull/272
    • Update pyproject.toml homepage link, add docs readme by @darrenburns in https://github.com/Textualize/textual/pull/268
    • Opacity rules by @darrenburns in https://github.com/Textualize/textual/pull/279
    • Tabs by @darrenburns in https://github.com/Textualize/textual/pull/293
    • Bump docs dev dependencies, add Tabs page, add note to docs README by @darrenburns in https://github.com/Textualize/textual/pull/301
    • Layout Resolver enhancement by @willmcgugan in https://github.com/Textualize/textual/pull/295
    • Implement CSS defaults by @willmcgugan in https://github.com/Textualize/textual/pull/294
    • Test animation by @willmcgugan in https://github.com/Textualize/textual/pull/303
    • Query dom - get child by @darrenburns in https://github.com/Textualize/textual/pull/306
    • Regions by @darrenburns in https://github.com/Textualize/textual/pull/319
    • Compositor refactor by @willmcgugan in https://github.com/Textualize/textual/pull/333
    • Add conversion to/from the CIE-L*ab color space. by @rodrigogiraoserrao in https://github.com/Textualize/textual/pull/360
    • Stringify the cast type, for <3.10 support by @tusharsadhwani in https://github.com/Textualize/textual/pull/351
    • WIP New color class by @willmcgugan in https://github.com/Textualize/textual/pull/349
    • Timer fix by @willmcgugan in https://github.com/Textualize/textual/pull/372
    • Custom scrollbars by @willmcgugan in https://github.com/Textualize/textual/pull/376
    • require semi-colons by @willmcgugan in https://github.com/Textualize/textual/pull/377
    • Logging server by @darrenburns in https://github.com/Textualize/textual/pull/366
    • Ensure filename is passed to devtools from init by @darrenburns in https://github.com/Textualize/textual/pull/383
    • tweak to log by @willmcgugan in https://github.com/Textualize/textual/pull/384
    • Redirect standard output to devtools server and logfile by @darrenburns in https://github.com/Textualize/textual/pull/385
    • Textual CLI by @darrenburns in https://github.com/Textualize/textual/pull/397
    • CSS align and box model by @willmcgugan in https://github.com/Textualize/textual/pull/398
    • optimize crop by @willmcgugan in https://github.com/Textualize/textual/pull/414
    • fix for showing scrollbars by @willmcgugan in https://github.com/Textualize/textual/pull/416
    • [css branch] Update _style_properties.py by @lllama in https://github.com/Textualize/textual/pull/415
    • fix for escape key processing by @willmcgugan in https://github.com/Textualize/textual/pull/420
    • [widget] Add a test for types of values we handle in style's size by @olivierphi in https://github.com/Textualize/textual/pull/428
    • [css][bugfix] CSS colors can now have digits at the end of their names by @olivierphi in https://github.com/Textualize/textual/pull/441
    • [layout][bugfix] Horizontal & Vertical layouts shouldn't display children that have display: none by @olivierphi in https://github.com/Textualize/textual/pull/436
    • button widget by @willmcgugan in https://github.com/Textualize/textual/pull/432
    • [colors] Add management of named Web colors to our CSS processing, prefix ANSI ones with ansi_ by @olivierphi in https://github.com/Textualize/textual/pull/443
    • Style error improvements by @darrenburns in https://github.com/Textualize/textual/pull/408
    • fix broken align and error logic by @willmcgugan in https://github.com/Textualize/textual/pull/446
    • Add TEXTUAL features env var by @willmcgugan in https://github.com/Textualize/textual/pull/448
    • [css] Add a "did you mean" suggestion when an unknown CSS property is spotted by @olivierphi in https://github.com/Textualize/textual/pull/445
    • Omit style property setter frames from tracebacks by @darrenburns in https://github.com/Textualize/textual/pull/457
    • Support 3 and 4 character hex strings for colours by @darrenburns in https://github.com/Textualize/textual/pull/459
    • [CI] Check that the "basic.py" sandbox script can be run for a few seconds without crashing by @olivierphi in https://github.com/Textualize/textual/pull/449
    • Skip CI-based MacOS devtools tests by @darrenburns in https://github.com/Textualize/textual/pull/461
    • Remove redundant import by @rjmill in https://github.com/Textualize/textual/pull/460
    • Add Python 3.10 to GitHub actions, upgrade mypy by @darrenburns in https://github.com/Textualize/textual/pull/462
    • Add links to CHANGELOG and fix date for v0.1.18 by @bbugyi200 in https://github.com/Textualize/textual/pull/454
    • Fix README.md typo disapointment->disappointment by @toonarmycaptain in https://github.com/Textualize/textual/pull/453
    • Fix broken overflow CSS rule by @darrenburns in https://github.com/Textualize/textual/pull/467
    • Update connection instructions in devtools header by @darrenburns in https://github.com/Textualize/textual/pull/469
    • Remove codecov from Textual by @darrenburns in https://github.com/Textualize/textual/pull/470
    • Windows CI by @darrenburns in https://github.com/Textualize/textual/pull/464
    • Tab focus by @willmcgugan in https://github.com/Textualize/textual/pull/458
    • [API] Start accepting PathLike objects here and there by @olivierphi in https://github.com/Textualize/textual/pull/463
    • line between logs by @willmcgugan in https://github.com/Textualize/textual/pull/478
    • added auto height by @willmcgugan in https://github.com/Textualize/textual/pull/476
    • CSS focus-within pseudo selector by @darrenburns in https://github.com/Textualize/textual/pull/477
    • diplay event method by @willmcgugan in https://github.com/Textualize/textual/pull/480
    • [tests] Add an integration test for the vertical layout, fix the bug that messes up the layout when the children have align: center top; by @olivierphi in https://github.com/Textualize/textual/pull/482
    • Added scroll_to_widget by @willmcgugan in https://github.com/Textualize/textual/pull/483
    • Scroll to top when widget is larger than container by @willmcgugan in https://github.com/Textualize/textual/pull/492
    • Add style param to Widget render method by @darrenburns in https://github.com/Textualize/textual/pull/479
    • [css] Add a "Did you mean" suggestion when the value of a color is wrong but we can find a close one by @olivierphi in https://github.com/Textualize/textual/pull/486
    • [tests][e2e] Add a test for Widget#scroll_to_widget() by @olivierphi in https://github.com/Textualize/textual/pull/494
    • Optimize Compositor by combining updates by @willmcgugan in https://github.com/Textualize/textual/pull/493
    • Msgpack devtools by @willmcgugan in https://github.com/Textualize/textual/pull/508
    • [App] Remove the focus timer: we now focus from a widget to the next/prev one instantly by @olivierphi in https://github.com/Textualize/textual/pull/505
    • added save_screenshot method and action by @willmcgugan in https://github.com/Textualize/textual/pull/511
    • Compositor deltas by @willmcgugan in https://github.com/Textualize/textual/pull/512
    • [css][scrollbar gutter] Manage the scrollbar-gutter: stable CSS property by @olivierphi in https://github.com/Textualize/textual/pull/501
    • Basic text input by @darrenburns in https://github.com/Textualize/textual/pull/495
    • [css] add "blank" border type by @olivierphi in https://github.com/Textualize/textual/pull/522
    • Auto dimensions by @willmcgugan in https://github.com/Textualize/textual/pull/527
    • Box fix by @willmcgugan in https://github.com/Textualize/textual/pull/532
    • Fix escape key by @willmcgugan in https://github.com/Textualize/textual/pull/534
    • compensated in box mode for scrollbars by @willmcgugan in https://github.com/Textualize/textual/pull/535
    • Mock time during integration tests by @olivierphi in https://github.com/Textualize/textual/pull/507
    • docs plugin by @willmcgugan in https://github.com/Textualize/textual/pull/536
    • Fix Option+Backspace hanging by @willmcgugan in https://github.com/Textualize/textual/pull/539
    • Text input improvements by @darrenburns in https://github.com/Textualize/textual/pull/528
    • [css] add scrollbar-size properties by @olivierphi in https://github.com/Textualize/textual/pull/529
    • [terminal buffering] Add support for the "mode 2026" - aka SynchronizedOutput by @olivierphi in https://github.com/Textualize/textual/pull/533
    • Refresh scrollbars on style changes. by @darrenburns in https://github.com/Textualize/textual/pull/545
    • Docs Refresh by @willmcgugan in https://github.com/Textualize/textual/pull/540
    • [AppTest] hotfix for the "css" branch after commit d45b0448880 by @olivierphi in https://github.com/Textualize/textual/pull/550
    • Swap ControlShiftUp & ControlShiftDown escape codes by @darrenburns in https://github.com/Textualize/textual/pull/549
    • Widget focus keybindings by @darrenburns in https://github.com/Textualize/textual/pull/546
    • Box model fractional by @willmcgugan in https://github.com/Textualize/textual/pull/552
    • simplify scrollbar dimensions by @willmcgugan in https://github.com/Textualize/textual/pull/553
    • Cache arrangements by @willmcgugan in https://github.com/Textualize/textual/pull/555
    • Fix scrollbar not updating with CSS animation by @willmcgugan in https://github.com/Textualize/textual/pull/558
    • Fix combined updates by @willmcgugan in https://github.com/Textualize/textual/pull/559
    • Inheritable CSS by @willmcgugan in https://github.com/Textualize/textual/pull/561
    • Scrolling nested containers by @darrenburns in https://github.com/Textualize/textual/pull/538
    • Support HSL colour space, allow spaces in RGB/HSL values by @darrenburns in https://github.com/Textualize/textual/pull/566
    • Support for bracketed paste mode by @darrenburns in https://github.com/Textualize/textual/pull/567
    • Make devtools deps extras, add note to internal ref docs, raise excep… by @darrenburns in https://github.com/Textualize/textual/pull/579
    • XTerm parsing improvements by @darrenburns in https://github.com/Textualize/textual/pull/570
    • Add success/warning/error button variants by @darrenburns in https://github.com/Textualize/textual/pull/575
    • [perf] Widget classes in textual.widget.__init__.py are now lazy-loaded by @olivierphi in https://github.com/Textualize/textual/pull/584
    • Tests around CSS specificity, and fix ordering in case of specificity clash by @darrenburns in https://github.com/Textualize/textual/pull/582
    • Adding space key to ansi sequences allows binding by @pvmm in https://github.com/Textualize/textual/pull/410
    • add space to keys by @willmcgugan in https://github.com/Textualize/textual/pull/585
    • Scroll view and DataTable Widget by @willmcgugan in https://github.com/Textualize/textual/pull/560
    • [tests] Restore layout integration tests by @olivierphi in https://github.com/Textualize/textual/pull/587
    • [button] Add a brief "active" effect when a button a clicked by @olivierphi in https://github.com/Textualize/textual/pull/588
    • Add a cursor to table by @willmcgugan in https://github.com/Textualize/textual/pull/591
    • User CSS should always take precedence over Widget CSS by @darrenburns in https://github.com/Textualize/textual/pull/595
    • Render cache by @willmcgugan in https://github.com/Textualize/textual/pull/602
    • Render enhancements by @willmcgugan in https://github.com/Textualize/textual/pull/606
    • Improvements to scroll_to_widget by @willmcgugan in https://github.com/Textualize/textual/pull/608
    • Small typo fix by @jacobtomlinson in https://github.com/Textualize/textual/pull/612
    • Color harmony by @willmcgugan in https://github.com/Textualize/textual/pull/619
    • Adds Layers and Docks by @willmcgugan in https://github.com/Textualize/textual/pull/627
    • Document CSS Styles by @willmcgugan in https://github.com/Textualize/textual/pull/629
    • Register callbacks at message pump level, invoke them after refresh by @darrenburns in https://github.com/Textualize/textual/pull/607
    • Focus order by @darrenburns in https://github.com/Textualize/textual/pull/638
    • restore missing callback by @willmcgugan in https://github.com/Textualize/textual/pull/649
    • Add remove by @willmcgugan in https://github.com/Textualize/textual/pull/653
    • center layout by @willmcgugan in https://github.com/Textualize/textual/pull/656
    • fix for layout bug by @willmcgugan in https://github.com/Textualize/textual/pull/662
    • unified events and messages by @willmcgugan in https://github.com/Textualize/textual/pull/660
    • CSS tie breaker by @willmcgugan in https://github.com/Textualize/textual/pull/665
    • partial tree control fix by @willmcgugan in https://github.com/Textualize/textual/pull/667
    • fix for footer by @willmcgugan in https://github.com/Textualize/textual/pull/670
    • Filling the gap between horizontal and vertical scrollbars by @darrenburns in https://github.com/Textualize/textual/pull/664
    • Screens API by @willmcgugan in https://github.com/Textualize/textual/pull/685
    • Improve error message for CSS syntax error by @darrenburns in https://github.com/Textualize/textual/pull/680
    • tests for auto refresh by @willmcgugan in https://github.com/Textualize/textual/pull/696
    • Docs scrollbar gutter by @darrenburns in https://github.com/Textualize/textual/pull/695
    • Animation callback by @darrenburns in https://github.com/Textualize/textual/pull/683
    • Docs content align by @darrenburns in https://github.com/Textualize/textual/pull/700
    • Docs intro by @willmcgugan in https://github.com/Textualize/textual/pull/703
    • Optimize applying CSS styles by @willmcgugan in https://github.com/Textualize/textual/pull/705
    • Docs layout by @darrenburns in https://github.com/Textualize/textual/pull/701
    • text-align CSS support by @darrenburns in https://github.com/Textualize/textual/pull/704
    • Values sections for CSS properties, some rewordings by @darrenburns in https://github.com/Textualize/textual/pull/713
    • table layout by @willmcgugan in https://github.com/Textualize/textual/pull/712
    • calculator example by @willmcgugan in https://github.com/Textualize/textual/pull/714
    • Delay transition by @darrenburns in https://github.com/Textualize/textual/pull/684
    • hotfix for justify by @willmcgugan in https://github.com/Textualize/textual/pull/717
    • Changes to opacity by @darrenburns in https://github.com/Textualize/textual/pull/720
    • CSS Path Relative by @darrenburns in https://github.com/Textualize/textual/pull/724
    • Log verbosity by @willmcgugan in https://github.com/Textualize/textual/pull/722
    • scrollbar fix by @willmcgugan in https://github.com/Textualize/textual/pull/726
    • Default css by @willmcgugan in https://github.com/Textualize/textual/pull/727
    • exclude invisible widgets by @willmcgugan in https://github.com/Textualize/textual/pull/728
    • private by @willmcgugan in https://github.com/Textualize/textual/pull/729
    • validate identifiers by @willmcgugan in https://github.com/Textualize/textual/pull/730
    • added char attribute to Text event by @willmcgugan in https://github.com/Textualize/textual/pull/732
    • App docs by @willmcgugan in https://github.com/Textualize/textual/pull/733
    • Fix auto height layout by @willmcgugan in https://github.com/Textualize/textual/pull/739
    • Make dark mode default by @darrenburns in https://github.com/Textualize/textual/pull/743
    • tree fix by @willmcgugan in https://github.com/Textualize/textual/pull/744
    • Easing preview by @darrenburns in https://github.com/Textualize/textual/pull/740
    • Code browser example by @willmcgugan in https://github.com/Textualize/textual/pull/746
    • Scroll issue by @willmcgugan in https://github.com/Textualize/textual/pull/747
    • focus level bindings by @willmcgugan in https://github.com/Textualize/textual/pull/751
    • App log by @willmcgugan in https://github.com/Textualize/textual/pull/753
    • Layout order by @willmcgugan in https://github.com/Textualize/textual/pull/755
    • Readme by @willmcgugan in https://github.com/Textualize/textual/pull/758
    • auto color by @willmcgugan in https://github.com/Textualize/textual/pull/763
    • Update various broken variables by @darrenburns in https://github.com/Textualize/textual/pull/764
    • Layer order by @willmcgugan in https://github.com/Textualize/textual/pull/765
    • fixes for variable css errors by @willmcgugan in https://github.com/Textualize/textual/pull/768
    • Add verbose tag to events docs by @darrenburns in https://github.com/Textualize/textual/pull/773
    • docs/widgets/Button by @darrenburns in https://github.com/Textualize/textual/pull/769
    • Grid cell margin by @darrenburns in https://github.com/Textualize/textual/pull/772
    • Docs styles by @willmcgugan in https://github.com/Textualize/textual/pull/775
    • Add docs for CSS variables by @darrenburns in https://github.com/Textualize/textual/pull/780
    • Fix broken text in docs by @darrenburns in https://github.com/Textualize/textual/pull/781
    • Initial layout guide stuff by @darrenburns in https://github.com/Textualize/textual/pull/748
    • Log drop critical by @willmcgugan in https://github.com/Textualize/textual/pull/782
    • Document styles by @darrenburns in https://github.com/Textualize/textual/pull/785
    • Minimise rendering when text-opacity/opacity is zero by @darrenburns in https://github.com/Textualize/textual/pull/774
    • Docs events by @willmcgugan in https://github.com/Textualize/textual/pull/787
    • changed to CSS_PATH by @willmcgugan in https://github.com/Textualize/textual/pull/789
    • Expand shrink by @willmcgugan in https://github.com/Textualize/textual/pull/794
    • Remove docks references & other tidying by @darrenburns in https://github.com/Textualize/textual/pull/795
    • Snapshot testing by @darrenburns in https://github.com/Textualize/textual/pull/793
    • Docs for widgets by @willmcgugan in https://github.com/Textualize/textual/pull/800
    • Docs input by @willmcgugan in https://github.com/Textualize/textual/pull/801
    • new align by @willmcgugan in https://github.com/Textualize/textual/pull/802
    • Docs actions by @willmcgugan in https://github.com/Textualize/textual/pull/804
    • Get widget by @willmcgugan in https://github.com/Textualize/textual/pull/808
    • New input by @willmcgugan in https://github.com/Textualize/textual/pull/811
    • optimizations for compositor by @willmcgugan in https://github.com/Textualize/textual/pull/812
    • Docs for reactivity by @willmcgugan in https://github.com/Textualize/textual/pull/815
    • Fix comma separated string in "Bindings" by @darrenburns in https://github.com/Textualize/textual/pull/797
    • Document widgets by @darrenburns in https://github.com/Textualize/textual/pull/819
    • Docs screen by @willmcgugan in https://github.com/Textualize/textual/pull/824
    • Bump 0.2.0 BETA by @willmcgugan in https://github.com/Textualize/textual/pull/822
    • change typing-extensions dependancy by @willmcgugan in https://github.com/Textualize/textual/pull/825
    • Too many "haves" by @driscollis in https://github.com/Textualize/textual/pull/827
    • Highlight import of Container class by @driscollis in https://github.com/Textualize/textual/pull/830
    • Fix some minor typos about the Stopwatch widget by @driscollis in https://github.com/Textualize/textual/pull/831
    • Py typed by @willmcgugan in https://github.com/Textualize/textual/pull/836
    • Note timers ID added to Container object by @kimvanwyk in https://github.com/Textualize/textual/pull/832
    • Highlight changed set_interval line in stopwatch06 example by @kimvanwyk in https://github.com/Textualize/textual/pull/833
    • Table polish by @willmcgugan in https://github.com/Textualize/textual/pull/837
    • Initialize reactive variables earlier by @willmcgugan in https://github.com/Textualize/textual/pull/838
    • fix error on exit from textual console by @willmcgugan in https://github.com/Textualize/textual/pull/841
    • Docs for Animator by @darrenburns in https://github.com/Textualize/textual/pull/840
    • Flag to enable header clock by @darrenburns in https://github.com/Textualize/textual/pull/843
    • Fix minor readability issue in modifying CSS class by @driscollis in https://github.com/Textualize/textual/pull/844
    • Regions optimize by @willmcgugan in https://github.com/Textualize/textual/pull/855
    • monochrome tests by @willmcgugan in https://github.com/Textualize/textual/pull/856
    • Fix issues with Styles.css, update "Grid" styles doc page by @darrenburns in https://github.com/Textualize/textual/pull/854
    • Docs queries by @willmcgugan in https://github.com/Textualize/textual/pull/857
    • DOM Queries typo squish by @davep in https://github.com/Textualize/textual/pull/858
    • Documenting comma-separated bindings in docstring and guide by @darrenburns in https://github.com/Textualize/textual/pull/853
    • Cli colors by @willmcgugan in https://github.com/Textualize/textual/pull/863
    • Typo fix: styles belong to a widget by @davep in https://github.com/Textualize/textual/pull/859
    • Support for key aliases, key handling tests by @darrenburns in https://github.com/Textualize/textual/pull/852
    • add max_idle for screen by @willmcgugan in https://github.com/Textualize/textual/pull/869
    • Update docs: fix copy/paste error for Timers by @lllama in https://github.com/Textualize/textual/pull/879
    • Provide extra hinting for App.query by @davep in https://github.com/Textualize/textual/pull/883
    • Document links by @darrenburns in https://github.com/Textualize/textual/pull/868
    • Win slow by @willmcgugan in https://github.com/Textualize/textual/pull/881
    • Harmonise the types of the App's css path declarations by @davep in https://github.com/Textualize/textual/pull/876
    • update borders with css by @willmcgugan in https://github.com/Textualize/textual/pull/889
    • docs: typos by @aaronst in https://github.com/Textualize/textual/pull/887
    • Fix :focus-within pseudo-selector by @darrenburns in https://github.com/Textualize/textual/pull/885
    • Move focus logic to screen, add more key replacements, collapse bindings in footer by @darrenburns in https://github.com/Textualize/textual/pull/880
    • Use screen offset instead of offset by @darrenburns in https://github.com/Textualize/textual/pull/893
    • Modify the screen examples to import Screen from textual.screen by @davep in https://github.com/Textualize/textual/pull/888
    • Fix _reset_focus being called on app instead of Screen by @darrenburns in https://github.com/Textualize/textual/pull/895
    • Fix textual run path bug on Windows by @darrenburns in https://github.com/Textualize/textual/pull/899
    • Remove unused code by @darrenburns in https://github.com/Textualize/textual/pull/896
    • depth first search by @willmcgugan in https://github.com/Textualize/textual/pull/902
    • Add password as a Input keyword argument by @davep in https://github.com/Textualize/textual/pull/911
    • CSS docs review - Layout by @davep in https://github.com/Textualize/textual/pull/913
    • CSS docs review - Events and Messages by @davep in https://github.com/Textualize/textual/pull/914
    • Reviewing CSS docs by @davep in https://github.com/Textualize/textual/pull/898
    • CSS docs review - CSS by @davep in https://github.com/Textualize/textual/pull/906
    • Get rid of string split key display, bug fix for not showing screen-level bindings by @darrenburns in https://github.com/Textualize/textual/pull/910
    • CSS docs review - Actions by @davep in https://github.com/Textualize/textual/pull/916
    • CSS docs review - Input by @davep in https://github.com/Textualize/textual/pull/915
    • CSS docs review - Styles by @davep in https://github.com/Textualize/textual/pull/904
    • CSS docs review - Reactivity by @davep in https://github.com/Textualize/textual/pull/918
    • README has 'development development' by @adam-huganir in https://github.com/Textualize/textual/pull/920
    • CSS docs review - Widgets by @davep in https://github.com/Textualize/textual/pull/921
    • CSS docs review - Animation by @davep in https://github.com/Textualize/textual/pull/922
    • CSS docs review - Screens by @davep in https://github.com/Textualize/textual/pull/923
    • CSS docs review - Styles reference by @davep in https://github.com/Textualize/textual/pull/925
    • CSS docs review - Events by @davep in https://github.com/Textualize/textual/pull/924
    • CSS docs review - Widgets reference by @davep in https://github.com/Textualize/textual/pull/926
    • Roadmap by @willmcgugan in https://github.com/Textualize/textual/pull/927
    • wait for mount by @willmcgugan in https://github.com/Textualize/textual/pull/912
    • fix cursor delete issue by @willmcgugan in https://github.com/Textualize/textual/pull/931
    • fix error with text-log in docs by @willmcgugan in https://github.com/Textualize/textual/pull/932
    • Some bug fixes in Input + add title to App constructor by @darrenburns in https://github.com/Textualize/textual/pull/934
    • Mention ordering of superpower methods in docs by @darrenburns in https://github.com/Textualize/textual/pull/935
    • fix focus glitch by @willmcgugan in https://github.com/Textualize/textual/pull/936
    • fix alignment bug by @willmcgugan in https://github.com/Textualize/textual/pull/937
    • Add directory of file to run to sys path by @darrenburns in https://github.com/Textualize/textual/pull/947
    • key bindings refactor by @willmcgugan in https://github.com/Textualize/textual/pull/941
    • Add support for action handlers prefixed with _ by @darrenburns in https://github.com/Textualize/textual/pull/946
    • Checkbox polishing + fix auto-width in Horizontal layout by @darrenburns in https://github.com/Textualize/textual/pull/942
    • Ensure scroll events are forwarded to the screen by @darrenburns in https://github.com/Textualize/textual/pull/948
    • Minor doc fixes by @MatrixManAtYrService in https://github.com/Textualize/textual/pull/938
    • docs: remove center layout by @aaronst in https://github.com/Textualize/textual/pull/949
    • Fix variables in Screens, remove dark reactive from Screen by @darrenburns in https://github.com/Textualize/textual/pull/957
    • Modify DOMNode.walk_children to return a list by @davep in https://github.com/Textualize/textual/pull/952
    • Try and better settle focus after a focused widget is removed (redux) by @davep in https://github.com/Textualize/textual/pull/954
    • Populate character on simulated key presses by @darrenburns in https://github.com/Textualize/textual/pull/960
    • Review the use of the bell in various examples and documentation files by @davep in https://github.com/Textualize/textual/pull/958
    • Post-PR #954 tidy up by @davep in https://github.com/Textualize/textual/pull/961
    • Fix bindings as tuples by @darrenburns in https://github.com/Textualize/textual/pull/962
    • Color animate alpha by @darrenburns in https://github.com/Textualize/textual/pull/964
    • Fix color preview by @darrenburns in https://github.com/Textualize/textual/pull/967
    • Update the calculator example to make all keyboard keys work again by @davep in https://github.com/Textualize/textual/pull/968
    • Initial pull of 5x5 into the Textual examples directory by @davep in https://github.com/Textualize/textual/pull/963
    • Switch the dark mode toggle to Ctrl+D by @davep in https://github.com/Textualize/textual/pull/970
    • adds demo by @willmcgugan in https://github.com/Textualize/textual/pull/959
    • docs: remove extra the by @aaronst in https://github.com/Textualize/textual/pull/976
    • added version number to demo, bumped beta by @willmcgugan in https://github.com/Textualize/textual/pull/977
    • Bump020 by @willmcgugan in https://github.com/Textualize/textual/pull/978
    • CSS by @willmcgugan in https://github.com/Textualize/textual/pull/979
    • lock update by @willmcgugan in https://github.com/Textualize/textual/pull/981
    • Abs readme links by @willmcgugan in https://github.com/Textualize/textual/pull/982

    New Contributors

    • @darrenburns made their first contribution in https://github.com/Textualize/textual/pull/213
    • @olivierphi made their first contribution in https://github.com/Textualize/textual/pull/428
    • @rjmill made their first contribution in https://github.com/Textualize/textual/pull/460
    • @bbugyi200 made their first contribution in https://github.com/Textualize/textual/pull/454
    • @toonarmycaptain made their first contribution in https://github.com/Textualize/textual/pull/453
    • @pvmm made their first contribution in https://github.com/Textualize/textual/pull/410
    • @jacobtomlinson made their first contribution in https://github.com/Textualize/textual/pull/612
    • @driscollis made their first contribution in https://github.com/Textualize/textual/pull/827
    • @kimvanwyk made their first contribution in https://github.com/Textualize/textual/pull/832
    • @davep made their first contribution in https://github.com/Textualize/textual/pull/858
    • @aaronst made their first contribution in https://github.com/Textualize/textual/pull/887
    • @adam-huganir made their first contribution in https://github.com/Textualize/textual/pull/920
    • @MatrixManAtYrService made their first contribution in https://github.com/Textualize/textual/pull/938

    Full Changelog: https://github.com/Textualize/textual/compare/v0.1.18...v0.2.0

    Source code(tar.gz)
    Source code(zip)
  • v0.1.18(Apr 30, 2022)

  • v0.1.17(Mar 10, 2022)

  • v0.1.16(Mar 10, 2022)

  • v0.1.15(Jan 31, 2022)

    Windows support has landed. Still experimental -- let us know if you run in to any problems!

    [0.1.15] - 2022-01-31

    Added

    • Added Windows Driver
    Source code(tar.gz)
    Source code(zip)
  • v0.1.14(Jan 9, 2022)

  • v0.1.13(Jan 1, 2022)

    [0.1.13] - 2022-01-01

    Fixed

    • Fixed spurious characters when exiting app https://github.com/willmcgugan/textual/issues/82
    • Fixed increasing delay when exiting
    Source code(tar.gz)
    Source code(zip)
  • v0.1.11(Sep 12, 2021)

    [0.1.11] - 2021-09-12

    Changed

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

    Added

    • 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

    • 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

    Changed

    • 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)

Owner
Will McGugan
I'm a full-stack software developer, and Python expert. Creator of Rich and @PyFilesystem.
Will McGugan
A simple todo GUI applicaiton

simple_todo_gui A simple todo GUI applicaiton To create an .exe file, run 'Python setup.py build' after installing PyQt5 and cx_Freeze with pip. Then

Dhammike Piyumal 2 Nov 11, 2021
Example GUI for Command line capable machine learning programs

Example GUI for Command line capable machine learning programs This is an example GUI made in PysimpleGUI and Tkinter, mainly for machine learning pro

Kim Yongwook 4 May 31, 2022
Dress up your code with a beautiful graphical user interface !

Dresscode Dress up your code with a beautiful graphical user interface ! This project is part of the Pyrustic Ecosystem. Look powered by the cyberpunk

20 Aug 24, 2022
A Virtual Desktop Assistant Written in Python

DesktopAssitant A Virtual Desktop Assistant Written in Python. It's generally a basic virtual assistant The basic purpose of this is to make work easi

Technerd brainiac 609 Jan 07, 2023
Tkinter calculetor - Tkinter calculetor with python

Tkinter_calculetor required to run py file pip install tkinter

Yasir Arafat 0 Feb 07, 2022
This program is written in python. It will help you find a valid solution for a sudoku puzzle.

Sudoku-Solver-Using-Tkinter This program is written in python. It will help you find a valid solution for a sudoku puzzle. Requirements: Python3 IDLE

Ankan Mahapatra 3 Oct 02, 2021
Basic browser based on PyQt5

goneDev-browser "basic browser based on PyQt5" This application is primarily built on macOS with more adaptibility for MacOS than Windows. v1.0 will s

Harsh ADV) 1 Jan 19, 2022
This a pythonTkinter GUI with sqlite3 Project.

FootballGym_MIS This a pythonTkinter GUI with sqlite3 Project. This software is useful if you want to enjoy running a gym. It helps you know which tea

Hikmatullah Mohammadi 2 Jun 19, 2022
A simple one-line quick entry GUI for your Obsidian daily notes in markdown format.

Quick-note-entry-for-Obsidian A simple one-line quick entry GUI for your Obsidian daily notes in markdown format. Log your day quickly with this simpl

Adrian Papineau 22 Oct 04, 2022
🧮A simple calculator written in python allows you to make simple calculations, write charts, calculate the dates, and exchange currency.

Calculator 🖩 A simple calculator written in python allows you to make simple calculations, write charts, calculate the dates, and exchange currency.

Jan Kupczyk 1 Jan 15, 2022
Plantasia, all your plants and muchrooms in one place!

Plantasia Project Description Tkinter GUI to be used as a repository for plants and muchrooms. It helps to optimize the search for species that have h

Marco Rodrigues 1 Dec 23, 2021
Learn to build a Python Desktop GUI app using pywebview, Python, JavaScript, HTML, & CSS.

Python Desktop App Learn how to make a desktop GUI application using Python, JavaScript, HTML, & CSS all thanks to pywebview. pywebview is essentially

Coding For Entrepreneurs 55 Jan 05, 2023
UI to save and load gnome-shell extension templates.

Gnome Extensions Loader GUI to save and load gnome shell extensions and extension settings. This app makes it easier to share your gnome extensions se

EMRECAN ALTINSOY 2 Nov 25, 2022
Create highly interactive web pages purely in Python

A package for building highly interactive user interfaces in pure Python inspired by ReactJS.

701 Jan 03, 2023
A calculator made using Python and Tkinter

Abacus Abacus is a calculator used to compute expressions with the operators of Addition, Subtraction, Multiplication and Division. It is named after

0 Jun 24, 2022
Win32mica: a simple module to add the Mica effect on legacy python windows.

Win32mica (aka PyMica): A simple module to add the Mica effect on legacy python windows The aim of this project is to apply the Mica effect on python

Martí Climent 40 Dec 13, 2022
PyCG: Practical Python Call Graphs

PyCG - Practical Python Call Graphs PyCG generates call graphs for Python code using static analysis. It efficiently supports Higher order functions T

Vitalis Salis 185 Dec 29, 2022
An qt asset browser for applications like houdini/nuke/maya/blender

AssetBrowser A qt asset browser for applications like houdini/nuke/maya/blender Currently in development Note: Only houdini plugin available during de

Jonas Sorgenfrei 6 Aug 05, 2022
Small Python scripts to take screenshot from a KaiOS/FFOS device and to mirror the screen of your phone.

This version of kaiscr is written by tkinter and can run in windows(use kailive-tk.py). "kailive-tk-speed.py" is speed optimization version. The sourc

openGiraffes Group 2 Mar 02, 2022
A GUI frontend developed in Python3 for simple admin tasks on MySQL-Server running on the localhost

A GUI frontend developed in Python3 for simple admin tasks on MySQL-Server running on the localhost. Developed for my CS School Project.

1 May 29, 2022