</> htmx 2.0 & Web Components: A Perfect Match for Frontend Development

A presentation at Jfokus in February 2025 in Stockholm, Sweden by Horacio Gonzalez

Slide 1

Slide 1

</> htmx 2.0 & Web Components A Perfect Match for Frontend Development

Slide 2

Slide 2

Horacio Gonzalez @LostInBrittany Espagnol Perdu en Bretagne

Slide 3

Slide 3

Create modern user interfaces with the simplicity and power of hypertext

Slide 4

Slide 4

Arbitrary Limitations of HTML ● Why can only <a> and <form> make HTTP(S) requests? ● Why can only click and submit events trigger them? ● Why are only GET and POST methods available? ● Why do <a> and <form> force a full page reload? ● Why so many arbitrary constraints in HTML?

Slide 5

Slide 5

Goal: Interactivity in Hypertext htmx extends HTML capabilities to: ● ● ● ● Perform AJAX requests Handle CSS transitions Work with WebSockets Process server-sent events All through declarative HTML attributes

Slide 6

Slide 6

But, what’s the point? It sounds nice and semantic, but what’s the real benefit?

Slide 7

Slide 7

A Quick Look Back A time when dinosaurs like me coded with Struts

Slide 8

Slide 8

Remember MVC? With its page-by-page navigation

Slide 9

Slide 9

The Golden Age of MVC Frameworks Generating HTML views

Slide 10

Slide 10

2005: The Arrival of AJAX The birth of Web 2.0

Slide 11

Slide 11

Web Pages Become Dynamic Apps Powered by JavaScript and jQuery

Slide 12

Slide 12

Shift to Single Page Applications (SPA)

Slide 13

Slide 13

Increasing Complexity The rise of JavaScript frameworks

Slide 14

Slide 14

Backend Becomes a REST API Serving JSON

Slide 15

Slide 15

We Gained Functionality But lost simplicity and semantics

Slide 16

Slide 16

Overkill for Many Applications Sometimes we just need a simple web page with a bit of interactivity

Slide 17

Slide 17

</> htmx Might Be the Right Solution It’s extended HTML ● Simplicity ● Semantics ● Interactivity

Slide 18

Slide 18

Too much theory, show us a demo! Examples, examples, examples! 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>

Slide 19

Slide 19

Too much theory, show us a demo! example-01.html https://github.com/LostInBrittany/introduction-to-htmx-and-lit

Slide 20

Slide 20

Sending POST on a button click ./html-examples/html-example-01.html 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>

Slide 21

Slide 21

GET, POST, PUT, DELETE… ./html-examples/html-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>

Slide 22

Slide 22

Using response to replace elements ./html-examples/html-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 disappear 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>

Slide 23

Slide 23

Choosing when to send requests ./html-examples/html-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>

Slide 24

Slide 24

More triggering options ./html-examples/html-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>

Slide 25

Slide 25

A spinner to ease you wait ./html-examples/html-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>

Slide 26

Slide 26

Des extensions presque à l’infini

Slide 27

Slide 27

Time for More Code! Let’s see a complete example

Slide 28

Slide 28

Too much theory, show us a demo! example-01.html https://github.com/LostInBrittany/introduction-to-htmx-and-lit

Slide 29

Slide 29

Let’s do a to-do list From Hello World to a To-do List

Slide 30

Slide 30

What the heck are web component? The 3 minutes context

Slide 31

Slide 31

Web Components Web standard W3C

Slide 32

Slide 32

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

Slide 33

Slide 33

Web Components Create your own HTML tags Encapsulating look and behavior

Slide 34

Slide 34

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

Slide 35

Slide 35

Web Components CUSTOM ELEMENTS SHADOW DOM TEMPLATES

Slide 36

Slide 36

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

Slide 37

Slide 37

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>

Slide 38

Slide 38

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);

Slide 39

Slide 39

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

Slide 40

Slide 40

Simple. Fast. Web Components

Slide 41

Slide 41

Modern lightweight web components For the new web paradigm

Slide 42

Slide 42

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

Slide 43

Slide 43

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

Slide 44

Slide 44

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

Slide 45

Slide 45

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

Slide 46

Slide 46

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

Slide 47

Slide 47

Too much theory, show us a demo! example-01.html https://github.com/LostInBrittany/introduction-to-htmx-and-lit

Slide 48

Slide 48

Custom Greeting example 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

Slide 49

Slide 49

My Lit Counter example Let’s do an interactive counter

Slide 50

Slide 50

Lit & </> htmx Love at first <tag>

Slide 51

Slide 51

htmx for structure, Lit to encapsulate logic To htmx, Lit elements are just regular tags

Slide 52

Slide 52

Too much theory, show us a demo! example-01.html https://github.com/LostInBrittany/introduction-to-htmx-and-lit

Slide 53

Slide 53

That’s all, folks! Thank you all! r u o ey v a e l e s a Ple ack! b d e e f