Hello! I’ve made a package called Dash Compose that gives an alternative way of writing dash layouts to the usual nested component constructors. A “hello world” example is given below, and you can read more about it (including some more complex/compelling use-cases) in the documentation here.
from dash import Dash, dcc, html
from dash.dependencies import Input, Output
from dash_compose import composition
@composition
def hello_world():
"""
<div>
<span>Hello </span>
<span>world!</span>
</div>
"""
with Div() as container:
yield Span("Hello ")
with Span():
yield "world!"
return container
app = Dash()
app.layout = hello_world()
if __name__ == "__main__":
app.run_server(debug=True)
Dash Compose was inspired by the way Textual and Dominate write layouts, which both reflect the tree-structure of HTML in your code. It also addresses some of my own experiences building/maintaining large Dash app codebases within a team.
Dash Compose is a bit magical in terms of how your code translates into component layouts, so I imagine some people will love it and others will hate it. Please both leave comments and suggestions!
Hi Adam! Yep, it’s made things much more readable than I’ve managed with vanilla dash code. Previously I was taking two approaches when defining layouts:
Introducing lots of variables to keep my code flat. E.g. if I wanted a modal, I’d define variables for all of the modal’s header components, then the modal header, then for the body components, then the modal body, and so on before assembling the modal itself. But this means the code is inside-out relative to the layout: The child components are defined before their parents. It can also wind up separating definitions of child components from their parents, meaning you have to move back and forth when reading the code.
Letting my components get deeply nested. But html component trees can get really deep, so I’d inevitably start defining collections of child components above those nested structures, repeating the child-before-parent issue and separating children from their parents again.
Dash Compose supports both approaches, but hopefully in a neater and more flexible way. If you want to nest components like in approach 2 you can do it using context managers. But within any of those nested contexts, you can then also start defining collections of components as variables like in approach 1 because the context block can have arbitrary code between your yield statements. This solves some of the children-before-parents issue because the context is the parent and it’s always before the child. It also helps with the separation of children and parents issue, because context nesting and yield statements provide clear visual flags for this relationship to the reader.
This is a great library! Heck, they should add this to base Dash.
One question: can @composition be used in combination with @callback to populate a component dynamically? Does it matter which decorator goes on the inside/outside?