# Provide / Consume URL: /docs/usage/provide-consume/ Section: usage Tags: usage, components, context -------------------------------------------------------------------------------- Provide / Consume {% provide %} and consume() let a parent push state that any descendant can read -- across slot boundaries, includes, and imported macros -- without passing it through every layer of parameters. Quick start {% provide theme = "dark" %} {{ consume("theme") }} {# "dark" #} {% endprovide %} provide pushes a value onto a per-key stack. consume reads the top of that stack, or returns a default if the key is absent. Syntax provide {% provide key = expr %} ...body... {% endprovide %} key -- a plain name (not a string). expr -- any expression: a literal, variable, function call, etc. The body can contain any template content. {% end %} is accepted as a shorthand for {% endprovide %}. consume {{ consume("key") }} {{ consume("key", default) }} key -- a string naming the provided value. default -- returned when no provider for that key is active. Defaults to None when omitted. Nesting and shadowing Providers nest. An inner provide with the same key shadows the outer one for the duration of its body, then the outer value is automatically restored: {% provide color = "red" %} {{ consume("color") }} {# "red" #} {% provide color = "blue" %} {{ consume("color") }} {# "blue" #} {% end %} {{ consume("color") }} {# "red" again #} {% end %} Independent keys coexist without interference: {% provide a = 1 %} {% provide b = 2 %} {{ consume("a") }}, {{ consume("b") }} {# 1, 2 #} {% end %} {% end %} Components: table + row The motivating use case is implicit configuration between paired components. A table provides alignment metadata that row consumes, so callers never pass alignment to every row by hand: {# components/table.html #} {% def table(headers, align=none) %} {% provide _table_align = align %} <table> <thead> <tr>{% for h in headers %}<th>{{ h }}</th>{% end %}</tr> </thead> <tbody>{% slot %}</tbody> </table> {% endprovide %} {% end %} {% def row(*cells) %} {% set align = consume("_table_align") %} <tr> {% for cell in cells %} <td{% if align %} class="align-{{ align[loop.index0] }}"{% endif %}> {{ cell }} </td> {% end %} </tr> {% end %} Usage: {% from "components/table.html" import table, row %} {% call table(headers=["Name", "Count"], align=["left", "right"]) %} {{ row("Alice", "42") }} {{ row("Bob", "17") }} {% end %} row never receives alignment as a parameter -- it reads it from the nearest table ancestor via consume. Theme provider pattern Another common pattern: a theme wrapper that sets context for all descendant components. {% def theme_provider(name="light") %} {% provide theme = name %} <div class="theme-{{ name }}">{% slot %}</div> {% endprovide %} {% end %} {% def button(label) %} <button class="btn btn-{{ consume("theme", "light") }}">{{ label }}</button> {% end %} Nested providers override the theme for their subtree: {% call theme_provider("dark") %} {{ button("Save") }} {# btn-dark #} {% call theme_provider("accent") %} {{ button("Upgrade") }} {# btn-accent #} {% end %} {{ button("Cancel") }} {# btn-dark (restored) #} {% end %} Where consume works Provided values are visible everywhere the render context is shared: Boundary Visible? Slot content ({% call %}...{% end %}) Yes Macro calls ({{ child() }}) Yes Imported macros ({% from "x.html" import y %}) Yes Includes ({% include "x.html" %}) Yes Child templates (inheritance) Yes Error safety provide compiles to a try/finally block, so the stack is always cleaned up -- even when the body raises an exception. After an error, a fresh render starts with a clean provider state. Naming conventions Use an underscore prefix for keys that are internal to a component pair: {% provide _table_align = align %} {# internal to table/row #} Use plain names for user-facing configuration: {% provide theme = "dark" %} Example A full working example is in examples/provide_consume/. -------------------------------------------------------------------------------- Metadata: - Word Count: 629 - Reading Time: 3 minutes