# Why partials It is Friday afternoon. The designer drops by with good news: the video card on your site is getting a small refresh. A rounded thumbnail, a view count with thousands separators, the author's name as a link. Fifteen minutes of work, they say. You open the templates folder and start counting. The home page has a card. The listing page has a card. The search results have a card. The "related videos" sidebar has a smaller card that is really the same card with a class on it. The email digest has a card too, and that one was copied from the listing page sometime last spring and never updated. You stop counting at fourteen. Every one of those cards started as a copy and paste, because Jinja templates made copying easy and reuse awkward. In Python you would never tolerate fourteen copies of a function. You would write it once, give it parameters, and call it. jinja_partials lets templates do exactly that: ``` html {% for v in videos %} {{ render_partial('shared/partials/video_square.html', video=v) }} {% endfor %} ``` [render_partial](../reference/render_partial.md#jinja_partials.render_partial) takes the path of a fragment file and the data it needs, renders it, and hands back safe HTML. The fragment sees `video` and nothing else. It cannot quietly depend on some page-level variable, because it never receives any. You can read its inputs at the call site, rename at the boundary (the loop's `v` becomes the card's `video`), and nest fragments inside fragments as deep as the design needs. The designer's fifteen minutes become fifteen minutes. # But Jinja already has include and macro It does, and both are nearly right, which is exactly why they are frustrating. `{% include %}` is a copy and paste that happens at render time. The fragment receives the entire context of whoever included it: every variable on the page, whether the fragment needs it or not. Nothing at the call site tells you what the fragment reads. Rename a variable on one page and the fragment breaks on that page only, and the fix is a `{% with %}` wrapper around the include, which is a parameter list wearing a disguise. `{% macro %}` gets the parameters right. The trouble is where macros live. A macro is defined inside a template file, so every page that wants the card has to `{% import %}` that file first. And a macro is not itself a template you can render. When HTMX asks your server for just one card to swap into the page, you cannot hand it a macro. With partials, the same `video_square.html` renders inside a page and also serves as a fragment response straight from a route, because it was a plain template all along. The original back-and-forth on this question is preserved in [issue \#1](https://github.com/mikeckennedy/jinja_partials/issues/1), if you enjoy that sort of thing. # What is in the box - One registration call per app, at startup. Flask, Quart, FastAPI, Starlette, or any Jinja2 environment you have lying around. - A `render_partial(template_name, **data)` global inside every template. It returns `Markup`, so autoescaping leaves your fragment alone. - The same function callable from Python, which makes a partial the easiest thing in your app to unit test. - Async apps are welcome. Quart, FastAPI, and Starlette with `enable_async=True` environments render partials on a small thread pool tied to the app's lifespan, and your templates do not change at all. The mechanics are in [How it works](how-it-works.md), and they are more interesting than they sound. Two minutes to [install](installation.md), then the [Quickstart](quickstart.md) builds that video card properly, once.