Htmx et Tailwind CSS

nora.nckm.eu

Illustration

Plutôt que de mettre en place un framework Javascript complexe tel que React, Vue, Angular, il est tout à fait possible de gérer le frontend d'une application web avec des technologies beaucoup plus simples. Les outils présentés ici permettent de créer des interfaces modernes, maintenables par un développeur seul ou une petite équipe. Ils sont utilisables directement en HTML, le but étant d'abstraire le Javascript et le CSS.

HTML + Htmx + Tailwind CSS = ❤️

L'idée est de revenir aux technologies de base du web que sont HTML et CSS afin de concevoir des sites plus réactifs, plus écoresponsables et plus durables. L'idéal étant de faire des sites statiques en optimisant les requêtes et les échanges de données avec le serveur et en limitant l'utilisation du Javascript.

HTML + Simple.css = ❤️❤️

Dans une démarche plus radicale, le protocole Gemini est encore plus minimaliste.

Gemtext = ❤️❤️❤️

Htmx

Htmx est une bibliothèque donnant accès à des fonctionnalités modernes du navigateur (AJAX, CSS Transitions, WebSockets, Server Sent Events) directement en HTML plutôt qu'en javascript.

Installation

L'installation consiste à copier la librairie et l'inclure dans le head de la page avec une balise script :

<script src="/path/to/htmx.min.js"></script>

La configuration peut ensuite se faire avec une balise meta :

<meta name="htmx-config" content='{"defaultSwapStyle":"outerHTML"}'>

Se référer à la documentation et à la référence.

Utilisation

Htmx envoie des requêtes AJAX et attend en retour des réponses HTML (fragments HTML). Htmx échange ensuite le HTML retourné avec la cible indiquée dans la page.

Request : définition de la requête (type et URL).

<!-- hx-get, hx-post, hx-put, hx-patch, hx-delete -->
<a hx-get="/link">Link</a>

Trigger : évènement déclenchant la requête.

<!-- hx-trigger -->
<div hx-get="/clicked" hx-trigger="click">Click Me</div>
<div hx-get="/clicked" hx-trigger="click[ctrlKey]">Click Me</div>
<input hx-get="/search" hx-trigger="keyup changed delay:500ms"/>
<div hx-get="/news" hx-trigger="every 3s"></div>
<div hx-get="/messages" hx-trigger="load delay:1s"></div>

Indicator : indicateur de requête en cours (icône de chargement).

<!-- hx-indicator -->
<button hx-get="/click">
    Click Me!
    <img class="htmx-indicator" src="/spinner.svg">
</button>

<button hx-get="/click" hx-indicator="#indicator">
    Click Me!
</button>
<img id="indicator" class="htmx-indicator" src="/spinner.svg"/>

Target : élément du DOM qui sera remplacé par le HTML retourné (élément portant la requête par défaut).

<!-- hx-target -->
<a hx-get="/link" hx-target="#results">Link</a>
<div id="results"></div>

Swapping : stratégie de remplacement entre la réponse et la cible d'une requête.

<!-- hx-swap -->
<div hx-get="/example" hx-swap="afterend"></div>
<div hx-get="/example" hx-swap="innerHTML swap:1s"></div>
<div hx-get="/example" hx-swap="beforeEnd scroll:bottom"></div>
<div hx-get="/example" hx-swap="innerHTML show:top" hx-target="#another-div"></div>

Synchronization : synchronisation de requêtes AJAX entre plusieurs éléments.

<!-- hx-sync -->
<form hx-post="/store">
    <input id="title" name="title" type="text"
        hx-post="/validate"
        hx-trigger="change"
        hx-sync="closest form:abort">
    <button type="submit">Submit</button>
</form>

Paramètre : paramètres inclus dans la requête. Par défaut, la valeur de l'élément ou les inputs d'un formulaire sont inclus.

Pour filtrer ou ajouter des paramètres à une requête :

<!-- hx-include, hx-params, hx-vals -->
<div hx-get="/example" hx-params="*"></div>
<div hx-get="/example" hx-vals='{"myVal": "My Value"}'>

<button hx-post="/send" hx-include="[name='email']">Send</button>
<input name="email" type="email"/>

Pour sélectionner les éléments d'une réponse qui remplaceront la cible :

<!-- hx-select, hx-select-oob -->
<button hx-get="/info" hx-select="#info-details" hx-swap="outerHTML">
    Get Info!
</button>

<div id="alert"></div>
<button hx-get="/info"
    hx-select="#info-details"
    hx-swap="outerHTML"
    hx-select-oob="#alert">
    Get Info!
</button>

Confirmation : fenêtre de confirmation

<!-- hx-confirm -->
<button hx-delete="/account" hx-confirm="Are you sure you wish to delete your account?">
    Delete My Account
</button>

Héritage : les attributs héritables s'appliquent à l'élément qui les porte ainsi qu'aux éléments enfants.

<div hx-confirm="Are you sure?">
    <button hx-delete="/account">Delete</button>
    <button hx-put="/account">Update</button>
    <button hx-get="/" hx-confirm="unset">Cancel</button>
</div>

Boost : conversion des liens et formulaires HTML classiques en requêtes AJAX ayant pour cible le body de la page.

<!-- hx-boost -->
<div hx-boost="true">
    <a href="/link">Link</a>
</div>

Historique : ajoute une URL dans l'historique du navigateur.

<!-- hx-push-url -->
<a hx-get="/link" hx-push-url="true">Link</a>

WebSockets et Server Sent Events :

<!-- hx-ws, hx-sse -->
<div hx-ws="connect:wss:/chatroom">
    <div id="chat_room">
        ...
    </div>
    <form hx-ws="send:submit">
        <input name="chat_message">
    </form>
</div>

<body hx-sse="connect:/news_updates">
    <div hx-get="/news" hx-trigger="sse:new_news"></div>
</body>

Tailwind CSS

Tailwind est un framework CSS basé sur des classes utilitaires plutôt que des classes par composant.

Les concepts du CSS doivent être assimilés puisqu'on les retrouve dans Tailwind. Les layouts flexbox et grid permettant de positionner les éléments sont particulèrement importants.

Installation

La procédure d'installation détaillée ici concerne Django. Pour l'installation dans un autre environnement se référer à la documentation officielle.

Module django-tailwind

Le module django-tailwind nécessite l'installation préalable de Node.js.

  1. Installation du module :

    pip install django-tailwind
    
  2. Ajout de l'app tailwind dans settings.xml :

    INSTALLED_APPS = [
        ...
        'tailwind',
    ]
    
  3. Initialisation de Tailwind : une configuration et une feuille de style minimales sont créées dans theme/static_src/tailwind.config.js et theme/static_src/src/style.css.

    python manage.py tailwind init
    
  4. Ajout de l'app theme dans settings.xml :

    INSTALLED_APPS = [
        ...
        'tailwind',
        'theme',
    ]
    
    TAILWIND_APP_NAME = 'theme'
    INTERNAL_IPS = [
        "127.0.0.1",
    ]
    
  5. Installation des dépendance de Tailwind : installe les dépendances Javascript avec npm.

    python manage.py tailwind install
    
  6. Démarrage de Tailwind : surveille les modifications de classes dans les fichiers HTML et génère à la volée la feuille de style dans theme/static/css/dist/styles.css.

    python manage.py tailwind start
    
  7. Déploiement de Tailwind : compile et minimise la feuille de style pour la production dans theme/static/css/dist/styles.css.

    python manage.py tailwind build
    
  8. Ajout de la feuille de style Tailwind dans le template de base :

    {% load tailwind_tags %}
    ...
    <head>
        ...
        {% tailwind_css %}
        ...
    </head>
    

Module pytailwindcss

Le module pytailwindcss ne dépend pas de Node.js, il utilise le client standalone officiel.

  1. Installation du module :

    pip install pytailwindcss
    
  2. Téléchargement du client :

    tailwindcss
    
  3. Initialisation de la configuration tailwind.config.js :

    tailwindcss init
    
  4. Initialisation de la feuille de style minimale tailwind.css :

    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    
  5. Démarrage de Tailwind : surveille les modifications de classes dans les fichiers HTML et génère à la volée la feuille de style.

    tailwindcss -i tailwind.css -o static/style.css --watch
    
  6. Déploiement de Tailwind : compile et minimise la feuille de style pour la production.

    tailwindcss -i tailwind.css -o static/style.css --minify
    
  7. Ajout de la feuille de style Tailwind dans le template de base :

    {% load static %}
    ...
    <head>
        ...
        <link rel="stylesheet" href="{% static 'style.css' %}">
        ...
    </head>
    

Le fichier tailwind.config.js contient la configuration : fichiers analysés, theme, plugins…

Le fichier tailwind.css contient les styles personnalisés : directives @tailwind, @layer, @apply

Utilisation

Les sources sont disponibles sur sourcehut.

Il suffit d'utiliser les classes utilitaires fournies par Tailwind directement dans les fichiers HTML. Il en existe de nombreuses qui sont listées dans la documentation. Voici quelques exemples :

<body class="bg-gray-100 flex flex-col xl:flex-row">
    <h1 class="text-blue-400">Lorem ipsum</h1>
    <p class="text-white bg-indigo-900">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
    <input type="text" class="bg-transparent border border-red-600" placeholder="…">

    <p class="text-md font-mono font-bold">Hello World</p>
    <p class="text-lg font-sans line-through">Hello World</p>
    <p class="text-4xl font-serif text-center">Hello World</p>
    <p class="text-6xl font-mono text-right italic font-extrabold">Hello World</p>

    <div class="bg-red-700 h-10 w-auto mr-10"></div>
    <div class="bg-green-700 h-16 w-4/6 my-10"></div>
    <div class="bg-blue-700 h-24 w-6/12 mx-auto"></div>
    <div class="border border-pink-400 h-40 w-56 mt-10 mx-auto">
        <h2 class="text-pink-700 p-16">Lorem ipsum</h2>
    </div>

    <nav class="flex justify-between items-center px-16 bg-purple-800 text-white h-24">
        <h1>Title</h1>
        <ul class="flex justify-between w-56">
            <a href="#">
                <li>Link</li>
            </a>
            <a href="#">
                <li>Link</li>
            </a>
            <a href="#">
                <li>Link</li>
            </a>
        </ul>
    </nav>

    <div class="h-32 w-32 mt-16 mx-auto lg:bg-orange-500 md:bg-red-500 sm:bg-purple-800"></div>
    <div class="h-32 w-32 mt-16 mx-auto lg:bg-orange-500 md:bg-green-800 sm:bg-indigo-300"></div>
    <div class="h-32 w-32 mt-16 mx-auto lg:bg-orange-500 md:bg-blue-200 sm:bg-teal-600"></div>
</body>

Simple.css

Simple.css est un framework CSS sans classe. Il permet de créer très rapidement des sites simples tels que des blogs ou des pages de présentation. Il ne contient pas de classes CSS, on code uniquement avec du HTML sémantique tout en profitant de fonctionnalités améliorées :

La feuille de style est très légère et peut être étendue en ajoutant une feuille de style personnalisée dans le head de la page :

<link rel="stylesheet" href="simple.min.css">
<link rel="stylesheet" href="simple.sub.css">

Le présent site utilise Simple.css et des pages HTML classiques.

Emojis

Un commentaire sur un de mes articles ? Commencez une discussion sur ma liste de diffusion en envoyant un email à ~nora/public-inbox@lists.sr.ht [règles]