</> htmx 2.0 & Web Components Un combo pour le développement web Horacio Gonzalez 2024-09-12

Horacio Gonzalez @LostInBrittany Espagnol Perdu en Bretagne

Créez des interfaces utilisateur modernes avec la simplicité et la puissance de l’hypertexte

Les limites arbitraires du HTML ● Pourquoi seules les balises <a> et <form> peuvent-elles effectuer des requêtes HTTP(S) ? ● Pourquoi seuls les événements de clic et d’envoi peuvent-ils les déclencher ? ● Pourquoi seules les méthodes GET et POST sont-elles disponibles ? ● Pourquoi les balises <a> et <form> forcent le remplacement de l’intégralité de l’écran ? ● Pourquoi autant des limites arbitraires à HTML ?

Objectif: de l’interactivité dans l’hypertexte htmx étend les fonctionnalités de HTML ● effectuer des requêtes AJAX ● effectuer des transitions CSS ● gérer des WebSockets ● gérer les événements envoyés par le serveur avec seulement des attributs HTML déclaratifs.

Mais à quoi ça sert tout ça ? Car c’est bien beau et sémantique, mais j’ai du mal à voir l’intérêt…

Et si on faisait un petit saut arrière dans le temps ? À une époque révolue, où les dinosaurs codaient avec struts

Souvenez-vous du modèle MVC Avec la navigation page par page

L’époque dorée d’une génération de frameworks Generant des vues HTML

Vers 2005 on voit arriver AJAX C’est la naissance du Web 2.0

Et les pages webs deviennent des apps dynamiques À coup de JavaScript, avec JQuery

On bascule vers des Single Page Apps

Des apps de plus en plus complexes Avec l’apparition des frameworks JavaScript

Et les backends deviennent des API REST Servant du JSON

On a gagné des fonctionnalités Mais on a perdu de la simplicité et le côté sémantique

Pour beaucoup d’app c’est overkill On ne veut qu’un site web avec un peu de dynamisme !

</> htmx peut être la bonne solution C’est du HTML étendu ● Simplicité ● Sémantique ● Dynamisme

On veut du code ! Des exemples ! Des exemples ! example-01.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <!— have a button that POST on a click via AJAX and replace the content of #status div with the response —> <button hx-post=”/clicked” hx-target=”#status”> Click Me </button> <div id=”status”>Not yet clicked</div>

Trop de blabla, on veut un exemple ! example-01.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <!— have a button that POST on a click via AJAX and replace the content of #status div with the response —> <button hx-post=”/clicked” hx-target=”#status”> Click Me </button> <div id=”status”>Not yet clicked</div>

GET, POST, PUT, DELETE… example-02.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <div> <button hx-get=”/test-methods” hx-target=”#status”>Send GET</button> <button hx-post=”/test-methods” hx-target=”#status”>Send POST</button> <button hx-put=”/test-methods” hx-target=”#status”>Send PUT</button> <button hx-delete=”/test-methods” hx-target=”#status”>Send DELETE</button> </div> <div id=”status”>No request sent</div>

Remplacer l’élément par la réponse example-03.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <div id=”test-replace”> <button hx-get=”/test-replace/innerHTML”> If you click, this message will be replaced </button> <button hx-get=”/test-replace/outerHTML” hx-swap=”outerHTML”> If you click, this button will become a div </button> <button hx-get=”/test-replace/delete” hx-swap=”delete”> If you click, this button will dissapear when the response is received </button> <button hx-get=”/test-replace/none” hx-swap=”none”> If you click, nothing changes, the response is ignored </button> </div>

Choisir quand émettre la requête example-04.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <!— By default, AJAX requests are triggered by the “natural” event of an element: —> <div id=”test-triggers”> <button hx-get=”/trigger/natural” hx-target=”#status”> In a button the natural event is a click </button> <button hx-trigger=”mouseover” hx-get=”/trigger/mouseover” hx-target=”#status”> This button triggers on mouseover </button> <button hx-trigger=”mouseenter” hx-get=”/trigger/mouseenter” hx-target=”#status”> This button triggers on mouseenter </button> <button hx-trigger=”mouseleave” hx-get=”/trigger/mouseleave” hx-target=”#status”> This button triggers on mouseleave </button> </div> <div id=”status”>No AJAX request sent yet</div>

Choisir quand émettre la requête example-05.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <!— By default, AJAX requests are triggered by the “natural” event of an element: —> <div id=”test-triggers”> <button hx-trigger=”every 5s” hx-get=”/trigger/5seconds” hx-target=”#status”> Sends request every 5 seconds, no event needed </button> <button hx-trigger=”click[ctrlKey]” hx-get=”/trigger/ctrlclick” hx-target=”#status”> Sends request on click while pressing Ctrl </button> <button hx-trigger=”click[ctrlKey] once” hx-get=”/trigger/ctrlclickonce” hx-target=”#status”> Sends request on the first click while pressing Ctrl </button> </div> <div id=”status”>No AJAX request sent yet</div>

Un spinner pour faire patienter example-06.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <!— By default, AJAX requests are triggered by the “natural” event of an element: —> <div id=”test-triggers”> <button hx-trigger=”every 5s” hx-get=”/trigger/5seconds” hx-target=”#status”> Sends request every 5 seconds, no event needed </button> <button hx-trigger=”click[ctrlKey]” hx-get=”/trigger/ctrlclick” hx-target=”#status”> Sends request on click while pressing Ctrl </button> <button hx-trigger=”click[ctrlKey] once” hx-get=”/trigger/ctrlclickonce” hx-target=”#status”> Sends request on the first click while pressing Ctrl </button> </div> <div id=”status”>No AJAX request sent yet</div>

Des extensions presque à l’infini

On veut du code ! Faisons un exemple

Tout le code est disponible https://github.com/LostInBrittany/introduction-to-htmx

Des démos de htmx Du Hello World à la To-do List

What the heck are web component? The 3 minutes context

Web Components Web standard W3C

Web Components Available in all modern browsers: Firefox, Safari, Chrome

Web Components Create your own HTML tags Encapsulating look and behavior

Web Components Fully interoperable With other web components, with any framework

Web Components CUSTOM ELEMENTS SHADOW DOM TEMPLATES

Custom Element To define your own HTML tag <body> … <script> window.customElements.define(‘my-element’, class extends HTMLElement {…}); </script> <my-element></my-element> </body>

Shadow DOM To encapsulate subtree and style in an element <button>Hello, world!</button> <script> var host = document.querySelector(‘button’); const shadowRoot = host.attachShadow({mode:’open’}); shadowRoot.textContent = ‘こんにちは、影の世界!’; </script>

Template To have clonable document template <template id=”mytemplate”> <img src=”” alt=”great image”> <div class=”comment”></div> </template> var t = document.querySelector(‘#mytemplate’); // Populate the src at runtime. t.content.querySelector(‘img’).src = ‘logo.png’; var clone = document.importNode(t.content, true); document.body.appendChild(clone);

But in fact, it’s just an element… ● ● ● ● Attributes Properties Methods Events

Simple. Fast. Web Components

Modern lightweight web components For the new web paradigm

LitElement import { LitElement, html } from ‘lit-element’; // Create your custom component class CustomGreeting extends LitElement { // Declare properties static get properties() { return { name: { type: String } }; } // Initialize properties constructor() { super(); this.name = ‘World’; } // Define a template render() { return html<p>Hello, ${this.name}!</p>; } } // Register the element with the browser customElements.define(‘custom-greeting’, CustomGreeting); Lightweight web-components using lit-html

Based on lit-html An efficient, expressive, extensible HTML templating library for JavaScript

Do you know tagged templates? function uppercaseExpression(strings, …expressionValues) { var finalString = ” for ( let i = 0; i < strings.length; i++ ) { if (i > 0) { finalString += expressionValues[i - 1].toUpperCase() } finalString += strings[i] } return finalString } const expressions = [ ‘Sophia Antipolis’, ‘RivieraDev’, ‘Thank you’]; console.log(uppercaseJe suis à ${expression[0]} pour ${expression[1]. $expression[2]! Little known functionality of template literals

lit-html Templates let myTemplate = (data) => html<h1>${data.title}</h1> <p>${data.body}</p>; Lazily rendered Generates a TemplateResult

It’s a bit like JSX, isn’t it? The good sides of JSX… but in the standard!

LitElement import { LitElement, html } from ‘lit-element’; // Create your custom component class CustomGreeting extends LitElement { // Declare properties static get properties() { return { name: { type: String } }; } // Initialize properties constructor() { super(); this.name = ‘World’; } // Define a template render() { return html<p>Hello, ${this.name}!</p>; } } // Register the element with the browser customElements.define(‘custom-greeting’, CustomGreeting); Lightweight web-components using lit-html

Une petit démo de Lit Faisons un compteur : my-lit-counter

Lit & </> htmx Amour au premier <tag>

htmx pour structure, lit pour encapsuler l’intelligence Pour htmx les élément lits sont comme n’importe quel tag

Une petit démo de htmx + Lit Faisons un compteur : my-lit-counter

That’s all, folks! Thank you all!