Skip to content

Animation

This chapter discusses how to use Textual's animation system to create visual effects such as movement, blending, and fading.

Animating styles

Textual's animator can change an attribute from one value to another in fixed increments over a period of time. You can apply animations to styles such as offset to move widgets around the screen, and opacity to create fading effects.

Apps and widgets both have an animate method which will animate properties on those objects. Additionally, styles objects have an identical animate method which will animate styles.

Let's look at an example of how we can animate the opacity of a widget to make it fade out. The following example app contains a single Static widget which is immediately animated to an opacity of 0.0 (making it invisible) over a duration of two seconds.

from textual.app import App, ComposeResult
from textual.widgets import Static


class AnimationApp(App):
    def compose(self) -> ComposeResult:
        self.box = Static("Hello, World!")
        self.box.styles.background = "red"
        self.box.styles.color = "black"
        self.box.styles.padding = (1, 2)
        yield self.box

    def on_mount(self):
        self.box.styles.animate("opacity", value=0.0, duration=2.0)


if __name__ == "__main__":
    app = AnimationApp()
    app.run()

The animator updates the value of the opacity attribute on the styles object in small increments over two seconds. Here's how the widget will change as time progresses:

AnimationApp Hello, World!

AnimationApp Hello, World!

AnimationApp Hello, World!

AnimationApp Hello, World!

Duration and Speed

When requesting an animation you can specify a duration or speed. The duration is how long the animation should take in seconds. The speed is how many units a value should change in one second. For instance, if you animate a value at 0 to 10 with a speed of 2, it will complete in 5 seconds.

Easing functions

The easing function determines the journey a value takes on its way to the target value. It could move at a constant pace, or it might start off slow then accelerate towards its final value. Textual supports a number of easing functions.

eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1XWVPjRlx1MDAxMH7nV1DeVyzmPrYqlYJcdTAwMDVcdTAwMTJcdTAwMDJLXHUwMDBlczib2ofBXHUwMDFh21x1MDAxM8uSkMZcdTAwMDaW4r+nJVx1MDAxM48vwrnUblX0YGumZ3q+6e6vu3Wztr7e8Ne5bbxfb9irjklcXFxcmMvGRjU/tkXpslx1MDAxNESkXHUwMDFll9mo6NQr+97n5fvNzaEpXHUwMDA21ueJ6dho7MqRSUo/il1cdTAwMTZ1suGm83ZY/lj9XHUwMDFlmaH9Ic+GsS+icEjTxs5nxeQsm9ihTX1cdNr/gvH6+k39O4POXHUwMDE0RTZcdTAwMDFWT1x1MDAwN3BKL05cdTAwMWVlaY1cdTAwMTMjrjSjWuDpXG5X7sBR3sYg7lx1MDAwMlxcXHUwMDFiJNVU42Tvl7TZ/nX76rh1fDDO+4j+dNVcdKd2XZK0/HUysYLp9EeFXHLS0lx1MDAxN9nAnrnY9/812sz8dF9syj5cdTAwMDCYiots1OuntqwuXHUwMDFmkGa56Th/XV9cdTAwMDNNZ03aq5WEmStcdTAwMThRwSMqXHUwMDE0XHUwMDE3XGZRQZhUU2m1n2lcdTAwMWNxXHUwMDAxcsyRRIxcdTAwMTK5gOxDloBcdTAwMWZcdTAwMDDZO1Q/XHUwMDAx2rnpXGZ6gC+Np2t8YdIyN1x1MDAwNXgrrLu8uzOONGZIXHUwMDEwPpX0rev1fWVcdTAwMGXCXCIlg6C0tVx1MDAxM7DCmiuhUZBUXHUwMDA35vtxXHUwMDFkXHUwMDBin1x1MDAxN43YN0V+Z6tGXHJsXHUwMDA2bDXcnVx0pLB5lMdm4nQsXHUwMDA0x1xcXHUwMDEzWtlqKk9cXDpcdTAwMDBhOkqSMJd1XHUwMDA2K+Kk9Kbw2y6NXdpb3GLT+Fx1MDAxZUliSv8hXHUwMDFiXHUwMDBlnVx1MDAwN1x1MDAxOL9lLvWLK2q9W1WQ962JV2ielS2yIa80XHUwMDA28lRPeFtcdTAwMGbRUlx1MDAwZqbvnzdWrm4uebGevXNg2L02+3+78UTa4pkwXFzkraCaIaxkYPZDvKUnh1x1MDAwN7y9d/7n3uFheaJHgra3+t9cdTAwMDFvRUQgXHUwMDE2pdRaXHUwMDAwbdlcdTAwMTJvMaFIYES1XHUwMDE0mi9cdTAwMDB7PdpShFwiKSmjclx1MDAwNXFxJCFtUEyWuEs5Ykpr9sbUhdAgwY7/U3dmwVxuR1ZPM/jwifRcdTAwMDXr2pXsRfL+skuYpkpjXHUwMDFj8utD9G3r38nu2cfty7//6F1cZoa7R1x1MDAwM3aQvDJ9y1xm+o7Xr7pUXHUwMDAwNSWjeJagNX2VjJCQXFxTRojmSC9cdTAwMDBcdTAwMGL0VYJY3XlcdH1pJKSCUsqpRFqH8lx1MDAxZqovXHUwMDAyMFx1MDAwNHMhJWGKXHUwMDEyvURmgpnAXHUwMDAyIf6mbFZcbmCrXHUwMDAw+Htj85zsVamMMYso4lpqSoRcdTAwMTYqNLHV06QogsZcdTAwMTZxJjWD5lx0yVx1MDAwN/VpXHUwMDEyKVwiJHTDoJJzzOb0YYVcIkisWFIou1x1MDAxMlx1MDAwYvVwqrkn6Gp1y/H2xMTj7ZVflXjEfVmnSjpcdTAwMDRcbkPoKlx1MDAxZUo6O+3Wyadd0vz482D3tDX+1L44z/Hzklx1MDAwZV5kx1dLOuDsiDBcdTAwMDZdPuJcdTAwMDRcbvB8q89cdHiRay5cdTAwMTTl0PD/R855acvAXHUwMDAyrJBklrt7wYggirFw2UcnlbJcdTAwMWE8M6lQKlmIlCcklW6W+pb7Ulx1MDAwN1x1MDAxNJqb3TNDl1xcz/mtjtHKUG5oZy1Z2rpsVlx1MDAxZjdza7dcdTAwMTLXS+uqarvzwe1cdTAwMWR8XHUwMDE1T8U+m7l3XHUwMDA3zjagrthfyjdZ4XouNcnxLI5nsYrcW8zhq1x1MDAxMVPIXG6Pp9Vps9y/lGdcdTAwMTe90+ukvfOlO+52bfNbp1x1MDAxNYH0x1x1MDAxNaZcXCqFkObznTiQKVx1MDAxMlxcK2jEXHUwMDE5NFLQkn81XnHyKF5BktaKMvyMYv1cdTAwMTJesSrLvlx1MDAxOa/GJlx1MDAxOX1cdTAwMTPEmlx1MDAwMJkwa+2uXCI2TJ63PNhcdTAwMDdcdTAwMTZMeFx1MDAwNi5w8d0lg7rG2NnL7eUoeNetn0przdaKXHUwMDE4tnLAze3a7T8uXFzYXHUwMDFjIn0= timevalue

Run the following from the command prompt to preview them.

textual easing

You can specify which easing method to use via the easing parameter on the animate method. The default easing method is "in_out_cubic" which accelerates and then decelerates to produce a pleasing organic motion.

Note

The textual easing preview requires the textual-dev package to be installed (using pip install textual-dev).

Completion callbacks

You can pass a callable to the animator via the on_complete parameter. Textual will run the callable when the animation has completed.

Delaying animations

You can delay the start of an animation with the delay parameter of the animate method. This parameter accepts a float value representing the number of seconds to delay the animation by. For example, self.box.styles.animate("opacity", value=0.0, duration=2.0, delay=5.0) delays the start of the animation by five seconds, meaning the animation will start after 5 seconds and complete 2 seconds after that.