Have you ever wished that Django’s include template tag could accept blocks of content?
I have.
Unfortunately, Django’s {% include %} tag doesn’t accept blocks of text.
Let’s look at a few possible solutions to this problem.
The Problem: Hack Include Workarounds
Let’s say we have HTML and CSS that make up a modal that is powered by Alpine.js and HTMX and we want to include this base modal template into many different templates for many different actions.
The problem is that the main content of our modal changes for different use cases.
We could try to fix this problem by breaking up our “include” into two parts (a top and a bottom).
Honestly, I think this solution isn’t a bad one.
Yes it is repetitive, but it’s so much easier to understand and maintain this big block of fairly straightforward HTML.
The biggest downside to this approach is that enhancements made to one of the styling and features of these various copy-pasted modals will likely diverge over time if we’re not careful to update all of them whenever we update one of them.
A Better Solution: Components
If I was using a component-based front-end web framework, I might be tempted to push all this logic into that front-end framework.
But I’m not using a component-based front-end front-end web framework and I don’t want to be forced to push any component-ish logic into the front-end.
I find this a lot easier to read than the include approach and a lot easier to maintain than the copy-pasted approach.
The Downsides: Too Much Magic
The biggest downside I see to django-cotton is that it’s a bit magical.
If you see <c-some-name> in a template, you need to know that this includes things from cotton/some_name.html.
There are lots of action at a distance issues that come up with Django, which can make it feel a bit magical but which are nonetheless worthwhile tradeoffs.
But this one also doesn’t look like a Django template tag, filter, or variable.
That feels very magical to me.
I’ve been enjoying trying out django-cotton over the past week and enjoying it.
Here are 2 other Django component libraries I have considered trying:
All Django component libraries (except for django-cotton) disallow line breaks between passed-in attributes due to a limitation of Django’s template tags (see below).
The Future: Multi-line Django Template Tags?
If Django’s template tags could be wrapped over multiple lines, we could create a library that worked like this:
But that first multi-line {% component %} tag is a big problem.
This is invalid in Django’s template language because tags cannot have linebreaks within them (see this old ticket, this discussion, and this new ticket):