Textual uses CSS to apply style to widgets. If you have any exposure to web development you will have encountered CSS, but don't worry if you haven't: this chapter will get you up to speed.
VSCode User?
The official Textual CSS extension adds syntax highlighting for both external files and inline CSS.
CSS stands for Cascading Stylesheet. A stylesheet is a list of styles and rules about how those styles should be applied to a web page. In the case of Textual, the stylesheet applies styles to widgets, but otherwise it is the same idea.
The first line is a selector which tells Textual which widget(s) to modify. In the above example, the styles will be applied to a widget defined by the Python class Header.
The lines inside the curly braces contains CSS rules, which consist of a rule name and rule value separated by a colon and ending in a semicolon. Such rules are typically written one per line, but you could add additional rules as long as they are separated by semicolons.
The first rule in the above example reads "dock: top;". The rule name is dock which tells Textual to place the widget on an edge of the screen. The text after the colon is top which tells Textual to dock to the top of the screen. Other valid values for dock are "right", "bottom", or "left"; but "top" is most appropriate for a header.
The DOM, or Document Object Model, is a term borrowed from the web world. Textual doesn't use documents but the term has stuck. In Textual CSS, the DOM is an arrangement of widgets you can visualize as a tree-like structure.
Some widgets contain other widgets: for instance, a list control widget will likely also have item widgets, or a dialog widget may contain button widgets. These child widgets form the branches of the tree.
With a header and a footer widget the DOM looks like this:
What we didn't show
We've simplified the above example somewhat. Both the Header and Footer widgets contain children of their own. When building an app with pre-built widgets you rarely need to know how they are constructed unless you plan on changing the styles of individual components.
Both Header and Footer are children of the Screen object.
To further explore the DOM, we're going to build a simple dialog with a question and two buttons. To do this we're going to import and use a few more builtin widgets:
fromtextual.appimportApp,ComposeResultfromtextual.containersimportContainer,Horizontalfromtextual.widgetsimportButton,Footer,Header,StaticQUESTION="Do you want to learn about Textual CSS?"classExampleApp(App):defcompose(self)->ComposeResult:yieldHeader()yieldFooter()yieldContainer(Static(QUESTION,classes="question"),Horizontal(Button("Yes",variant="success"),Button("No",variant="error"),classes="buttons",),id="dialog",)if__name__=="__main__":app=ExampleApp()