---
title: "Order, Tailwind, DRY"
date: 2024-12-14
tags:
  - post
  - python
  - javascript
---

(Order in the CSS rule sense, not the metaphysical sense.)

The time has come to begin exfiltrating some higher-traffic, higher-leverage parts of Buttondown's admin UI away from the autogenerated Django admin and into some more bespoke components.

Take, for instance, this rather grisly (but useful) inline admin table:

![](/img/django-admin.png)

This contains useful information but is annoying to parse. It gets replaced with the following HTML, all still governed by Django and a wallop of Tailwind [^1]:

<script src="https://cdn.tailwindcss.com"></script>
<div class="not-prose">
<ol class="items-center sm:flex ml-0 list-none p-4 border border-solid border-[var(--ui-color)]">
    <li class="relative sm:mb-0 flex-1">
        <div class="flex items-center">
            <div class="z-10 flex items-center justify-center w-6 h-6 bg-blue-100 rounded-full ring-0 ring-white dark:bg-blue-900 sm:ring-8 dark:ring-gray-900 shrink-0">
            </div>
            <div class="sm:flex w-full bg-gray-200 h-0.5 dark:bg-gray-700"></div>
        </div>
        <div class="mt-3 sm:pe-8">
            <h3 class="text-md font-semibold text-gray-900 dark:text-white">draft</h3>
            <time class="block text-sm font-normal leading-none text-gray-400 dark:text-gray-500">8:14 p.m.</time>
        </div>
    </li>
    <li class="relative sm:mb-0 flex-1 last:text-right group">
        <div class="flex items-center">
            <div class="z-10 flex items-center justify-center w-6 h-6 bg-blue-100 group-last:bg-blue-500 rounded-full ring-0 ring-white dark:bg-blue-900 sm:ring-8 dark:ring-gray-900 shrink-0">
            </div>
            <div class="sm:flex w-full bg-gray-200 h-0.5 dark:bg-gray-700 group-last:order-first"></div>
        </div>
        <div class="mt-3 sm:pe-8 group-last:pe-0">
            <h3 class="text-md font-semibold text-gray-900 dark:text-white">about_to_send</h3>
            <time class="block text-sm font-normal leading-none text-gray-400 dark:text-gray-500">8:16 p.m.</time>
        </div>
    </li>
    <li class="relative sm:mb-0 flex-1 last:text-right group">
        <div class="flex items-center">
            <div class="z-10 flex items-center justify-center w-6 h-6 bg-blue-100 group-last:bg-blue-500 rounded-full ring-0 ring-white dark:bg-blue-900 sm:ring-8 dark:ring-gray-900 shrink-0">
            </div>
            <div class="sm:flex w-full bg-gray-200 h-0.5 dark:bg-gray-700 group-last:order-first"></div>
        </div>
        <div class="mt-3 sm:pe-8 group-last:pe-0">
            <h3 class="text-md font-semibold text-gray-900 dark:text-white">in_flight</h3>
            <time class="block text-sm font-normal leading-none text-gray-400 dark:text-gray-500">8:18 p.m.</time>
        </div>
    </li>
    <li class="relative sm:mb-0 flex-1 last:text-right group">
        <div class="flex items-center">
            <div class="z-10 flex items-center justify-center w-6 h-6 bg-blue-100 group-last:bg-blue-500 rounded-full ring-0 ring-white dark:bg-blue-900 sm:ring-8 dark:ring-gray-900 shrink-0">
            </div>
            <div class="sm:flex w-full bg-gray-200 h-0.5 dark:bg-gray-700 group-last:order-first"></div>
        </div>
        <div class="mt-3 sm:pe-8 group-last:pe-0">
            <h3 class="text-md font-semibold text-gray-900 dark:text-white">sent</h3>
            <time class="block text-sm font-normal leading-none text-gray-400 dark:text-gray-500">8:20 p.m.</time>
        </div>
    </li></ol>
</div>

It's a trivial thing, but lets me pull out a new toy that I learned from [Mary](https://mary.my.id/) a few weeks back: [`order`](https://tailwindcss.com/docs/order), which lets you re-arrange the rendering order of elements in a `flex` container irrespective of their original order.

For instance, consider the following:

```html
<div class="flex gap-1">
  <div class="order-2">world</div>
  <div class="order-1">hello</div>
</div>
```

This, as you might expect, renders as:

<div class="bg-gray-50 border border-gray-300 p-4 flex items-center">
<div class="flex gap-1">
    <div style="order: 2">world</div>
    <div style="order: 1">hello</div>
</div>
</div>

Where this gets really useful is composition with `groups`. Consider the following:

```html
<div class="flex gap-1 w-[200px]">
  <div class="group flex-1 flex items-center">
    <div class="z-10 flex items-center justify-center size-6 bg-red-500"></div>
    <div class="w-full bg-gray-200 h-0.5"></div>
  </div>
  <div class="group flex-1 flex items-center">
    <div class="z-10 flex items-center justify-center size-6 bg-red-500"></div>
    <div class="w-full bg-gray-200 h-0.5"></div>
  </div>
  <div class="group flex-1 flex items-center">
    <div class="z-10 flex items-center justify-center size-6 bg-red-500"></div>
    <div class="w-full bg-gray-200 h-0.5"></div>
  </div>
</div>
```

This renders, unexcitingly, as:

<div class="bg-gray-50 border border-gray-300 p-4 flex items-center">
<div class="flex gap-1 w-[200px] flex-1">
  <div class="group flex-1 flex items-center">
    <div class="z-10 flex items-center justify-center size-6 bg-red-500"></div>
    <div class="w-full bg-gray-200 h-0.5"></div>
  </div>
  <div class="group flex-1 flex items-center">
    <div class="z-10 flex items-center justify-center size-6 bg-red-500"></div>
    <div class="w-full bg-gray-200 h-0.5"></div>
  </div>
  <div class="group flex-1 flex items-center">
    <div class="z-10 flex items-center justify-center size-6 bg-red-500"></div>
    <div class="w-full bg-gray-200 h-0.5"></div>
  </div>
</div>
</div>

But! Add a tiny sprinkle of `group-last:`

```html
<div class="flex gap-1 w-[200px]">
  <div class="group flex-1 flex items-center">
    <div
      class="z-10 flex items-center justify-center size-6 bg-red-500 group-last:bg-blue-500"
    ></div>
    <div class="w-full bg-gray-200 h-0.5 group-last:order-first"></div>
  </div>
  <div class="group flex-1 flex items-center">
    <div
      class="z-10 flex items-center justify-center size-6 bg-red-500 group-last:bg-blue-500"
    ></div>
    <div class="w-full bg-gray-200 h-0.5 group-last:order-first"></div>
  </div>
  <div class="group flex-1 flex items-center">
    <div
      class="z-10 flex items-center justify-center size-6 bg-red-500 group-last:bg-blue-500"
    ></div>
    <div class="w-full bg-gray-200 h-0.5 group-last:order-first"></div>
  </div>
</div>
```

And you get:

<div class="bg-gray-50 border border-gray-300 p-4 flex items-center">
<div class="flex gap-1 w-[200px] flex-1">
  <div class="group flex-1 flex items-center">
    <div class="z-10 flex items-center justify-center size-6 bg-red-500 group-last:bg-blue-500"></div>
    <div class="w-full bg-gray-200 h-0.5 group-last:order-first"></div>
  </div>
  <div class="group flex-1 flex items-center">
    <div class="z-10 flex items-center justify-center size-6 bg-red-500 group-last:bg-blue-500"></div>
    <div class="w-full bg-gray-200 h-0.5 group-last:order-first"></div>
  </div>
  <div class="group flex-1 flex items-center">
    <div class="z-10 flex items-center justify-center size-6 bg-red-500 group-last:bg-blue-500"></div>
    <div class="w-full bg-gray-200 h-0.5 group-last:order-first"></div>
  </div>
</div>
</div>

Obviously, that is a lot of HTML to write for a very simple outcome. There are a bunch of ways you could reduce this. Why so much repetition? Why specify `group-last` for every node when you _know_ it's going to be the last one?

Because in reality, the above HTML is actually, in Django, a pure and concise `for` loop:

```html
<div class="flex gap-1 w-[200px]">
  {\% for item in items \%}
  <div class="group flex-1 flex items-center">
    <div
      class="z-10 flex items-center justify-center size-6 bg-red-500 group-last:bg-blue-500"
    ></div>
    <div class="w-full bg-gray-200 h-0.5 group-last:order-first"></div>
  </div>
  {\% endfor \%}
</div>
```

Which suddenly looks much more pleasant and maintainable than its conditionally-rendered alternative:

```html
<div class="flex gap-1 w-[200px]">
  {\% for item in items \%}
  <div class="group flex-1 flex items-center">
    <div
      class="z-10 flex items-center justify-center size-6 {\% if forloop.last \%} bg-blue-500 {\% else \%} bg-red-500 {\% endif \%}"
    ></div>
    <div
      class="w-full bg-gray-200 h-0.5 {\% if forloop.last \%} order-first {\% endif \%}"
    ></div>
  </div>
  {\% endfor \%}
</div>
```

[^1]: Not mobile friendly, I'm afraid! Not exactly a pressing concern for the admin site at the moment.
