Textual - An Intro to DOM Queries (Part II)
Last week, you learned the basics of Textual’s DOM queries. If you missed it, you can read the article now!
In this tutorial you will be learning about the following topics:
The DOMQuery object
Getting the first or last widget
Query filters
Query exclusions
Other query methods
Let’s get started!
The DOMQuery Object
The DOMQuery object gets returned whenever you call query(). The DOMQuery object works just like a Python list and supports all the same operations that you do with a list:
query[1]len(query)reverse(query)etc
However, DOMQuery has additional methods of its very own. You can get a list of these methods using Python’s dir() function against the DOMQuery object.
To see this in action, create a new file named domquery_methods.py in your Python IDE and add this code:
Here, you loop over all the entries that dir() returns and add them to your string. Then, you update the Label as before.
When you run this code, you will see something like this:
Let’s spend a few moments learning about the most helpful methods from this list!
Getting the First or Last Widget
Textual’s DOMQuery object has a couple of handy methods you can use to get the first or last matching widget. You may have noticed them in the output from the previous code example. They are called: first() and last().
You can take the example code from earlier with three buttons and update it slightly to ask what the first and last widgets are. For this example, you will name the file first_and_last.py and use this code:
To make everything explicit, you add an id to all the Button widgets. Then, in on_button_pressed(), you grab the first and last widgets from the DOMQuery object and put them in the Label.
When you run this code and press any of the buttons, you will see something like this:
Of course, you don’t need to use first() and last() if you don’t want to because the DOMQuery object behaves like a list. You could use widgets[0] and widgets[-1] to get the first and last widgets if you want to instead.
However, there are benefits to using these methods. For example, you can pass in an expect_type argument to first() and last(), making this even more explicit about what type you expect the first and last widgets to be.
Here’s an example that expects the last widget to be a Button:
last_button = self.query().last(Button)If the last widget is not a Button, you will receive a WrongType exception.
Query Filters
Textual also provides a filter() method that you may use on your DOMQuery objects. As you might expect, the filter() is useful for getting subsets of widgets from the query list.
Here is an example where you run a query to get all the widgets, and then you extract the Label and the Button widgets into new DOMQuery objects:
Query Exclusions
You may exclude widgets from a DOMQuery using the exclude() method. You can think of exclude() as the logical opposite of filter(). It will remove any widgets from the DOMQuery that match a CSS selector.
You can use the previous example, where you get all the widgets. However, this time, you want to exclude all the Button widgets.
Here’s one way you could do that:
# Get all the widgets
widgets = self.query()
# Exclude the buttons
non_buttons = widgets.exclude(”Button”)With a little practice, you can soon filter and exclude as many or as few widgets as you want from your query set.
Other Query Methods
So far, you have seen how to get list-like DOMQuery objects that you can loop over and call each widget’s own method on. However, the DOMQuery object supports several methods that you can run, which will update all the matched widgets without needing to loop over them.
A good example in the Textual documentation mentions you can use add_class() to mark widgets as “started” or “ended”. Here’s an example:
self.query(”Input”).add_class(”started”)Of course, you could add any other CSS class to all your widgets, too.
Here is a list of all the methods you can use that will affect everything in the query set:
add_class- Add a CSS class or classes.blur- Removes the focus from the widgets you matched.focus- Focuses the first matching widgets. It’s kind of the opposite ofblur.refresh- Need to refresh a set of widgets? Use this method!remove_class- Removes a CSS class. In other words, if you disabled your widgets withadd_class(), you could re-enable them with this one.remove- Remove all the matched widgets from the DOM.set_class- Sets a CSS class or classes on your widget query setset- Sets common attributes on your widgets. For example, you can setdisplay,visible,disabled, orloading.toggle_class- Sets a CSS class or classes if it is not already set or vice-versa
You will need to spend some time trying each of these out. You can use the code examples in this chapter and try calling them against various DOMQuery objects. If you need a reminder of what pre-built classes are available to you, refer to chapter three under pseudo classes or check the Textual documentation.
Wrapping Up
Learning how to use DOM queries in Textual will help you whenever you need to do bulk updates to widgets in your application. You will be using some kind of query in most of the applications you build, so understanding how to use them can only help you be more effective.
Let’s review what you learned:
The DOMQuery object
Getting the first or last widget
Query filters
Query exclusions
Other query methods
Now that you have a good grounding in working with the DOMQuery object, you should spend some time reviewing the code in this chapter and utilizing the methods you learned about. Give them a try, and you’ll be ready to make bulk updates to your user interface in no time!
Learn More
Want to learn more about Textual? Check out my book:






