pythontextualpython-textual

Adding Status text to a (Textual) Footer


I'm trying to create an enditor where the Footer contains the usual bindings on the left and some status information on the right, for example the line number. The Footer in textual is very simple so I thought to extend it, but I'm unable to see both my label and the binding of the base Footer. This is my code:

class MyFooter(Footer):
  DEFAULT_CSS = """
  MyFooter {
    
    .right-label {
        text-align: right;    
    }
  }
  """

  def compose(self) -> ComposeResult:
    for widget in super().compose():
        yield widget
    yield Label("This is the right side label", id="right-label")

To test it, you can use the first example of the tutorial:

from textual.app import App, ComposeResult
from textual.widgets import Header, Footer,Label

class MyFooter(Footer):
  DEFAULT_CSS = """
  MyFooter {
    
    .right-label {
        text-align: right;    
    }
  }
  """

  def compose(self) -> ComposeResult:
    """Create child widgets for the footer."""
    for widget in super().compose():
        yield widget
    yield Label("This is the right side label", id="right-label")

 class StopwatchApp(App):
   """A Textual app to manage stopwatches."""

   BINDINGS = [("d", "toggle_dark", "Toggle dark mode")]

   def compose(self) -> ComposeResult:
     """Create child widgets for the app."""
     yield Header()
     yield MyFooter()

   def action_toggle_dark(self) -> None:
     """An action to toggle dark mode."""
     self.dark = not self.dark


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

Solution

  • I'd recommend solving this by laying out multiple widgets, instead of overriding the Footer class.

    The Footer widget uses dock: bottom; layout: grid; grid-columns: auto, which makes this a little tricky. But you can wrap the Footer in a fixed-sized container, and lay out your label next to that.

    from textual.app import App, ComposeResult
    from textual.widgets import Header, Footer, Label
    from textual.containers import Horizontal
    
    
    class StopwatchApp(App):
        """A Textual app to manage stopwatches."""
    
        BINDINGS = [("d", "toggle_dark", "Toggle dark mode")]
        CSS = """
            Horizontal#footer-outer {
                height: 1;
                dock: bottom;
            }
            Horizonal#footer-inner {
                width: 75%;
            }
            Label#right-label {
                width: 25%;
                text-align: right;
            }
        """
    
        def compose(self) -> ComposeResult:
            """Create child widgets for the app."""
            yield Header()
            with Horizontal(id="footer-outer"):
                with Horizontal(id="footer-inner"):
                    yield Footer()
                yield Label("This is the right side label", id="right-label")
    
        def action_toggle_dark(self) -> None:
            """An action to toggle dark mode."""
            self.dark = not self.dark
    
    
    if __name__ == "__main__":
        app = StopwatchApp()
        app.run()
    

    Screenshot of the app