JavaScript Component-Inspired Django Templates

When I was starting out writing Cassette Nest, I went back and forth with “real” code as well as prototypes using React and Vue.

I have a UI concept that I use throughout the app called a “card.” It’s a big, blocky interface that spans the width of the screen. It could show information about a camera, a roll of film, or a project (among other things).

Because I’m developing all of Cassette Nest to work without JavaScript, I needed to convert my prototypes to Django templates.

I built a template for a card that acts very much like a JavaScript component. Every type of card uses the same template, but its appearance will change depending on the values passed into it (similar to props in Vue or React).

Here are a few ways I include the template (note the Sass-inspired _ in the filename to indicate that it’s intended to be used as an include.):

{% include '_card.html' with name='Dashboard' location=dashboard_url %}

{% include '_card.html' with name='Ready to process' location=ready_url slot='count' count=rolls_ready_count %}

{% include '_card.html' with name='In storage' location=inventory_url slot='count' count=rolls_storage_count %}

{% include '_card.html' with name=roll.camera.name location=roll_detail slot='reminder' roll=roll %}

Here’s (a simplified version of) the template itself:

<section class="c-card c-card--{# ... #}"&gt;
  {% if project and film %}
    <form onsubmit="{# ... #}" action="{# ... #}" method="post"&gt;
      {# ... #}
      <input type="submit" value="Remove" /&gt;
    </form&gt;
  {% endif %}
  <a href="{# ... #}"&gt;
    <header&gt;<h1&gt;{{ name }}</h1&gt;</header&gt;
    {% if slot == 'count' %}
      <div class="c-card__count" title="Number of rolls"&gt;
        <span&gt;{# ... #}</span&gt;
      </div&gt;
    {% elif slot == 'reminder' %}
      <section class="c-reminder c-reminder--{# ... #}"&gt;
        <header&gt;
          {% if roll.film.iso %}
            <h1 title="{{ roll.film.type|upper }}"&gt;
              {{ roll.film.iso }}
            </h1&gt;
          {% endif %}
        </header&gt;
      </section&gt;
    {% endif %}
  </a&gt;
</section&gt;

(Please forgive any incorrect document outlines. I’m working on that.)

Note my use of OOCSS-ish / BEM-style classes. That makes writing nested Sass very nice.

.c-card {
    // ...
    &--film {
        // ...
    &__count {
        // ...

Here are some of the ways cards can look:

Screen shot showing a film inventory item with its number of rolls
Inventory Item showing name, number of rolls, and type of film (background color indicating color negative film)
Screenshot of a project item showing its name and number of rolls of film
Project showing how number of rolls of film
Screenshot showing a camera and what type of film is loaded in it
Loaded Camera with a “reminder” tab showing film type (background color indicating black and white) and ISO

I’ve since expanded the concept to certain form fields, which hasn’t been quite as easy of a drop-in solution so far, but it’s a lot easier than duplicating a lot of HTML where it does work.

Look how clean this is!

{% for field in form %}
  {% include '_form-field.html' with field=field %}
{% endfor %}

And here’s how it’s defined in the template.

<div class="c-field {# ... #}"&gt;
  <label for="{{ field.id_for_label }}"&gt;{{ field.label }}</label&gt;
  <div class="c-field__widget"&gt;
    {{ field }}
    {% if field.help_text %}
      <small&gt;{{ field.help_text }}</small&gt;
    {% endif %}
  </div&gt;
</div&gt;

Anyway, I’m liking this technique and wanted to share it! Is anybody else building pseudo-components in their back-end templates like this?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s