'htm is JSX-like syntax in plain JavaScript', but...

artydev - Feb 16 '22 - - Dev Community

HTM stands for 'Hyperscript Tagged Markup', written by Jason Miller,
who is also the creator of the awesome library Preact.

Here is how to use it :

import { render } from 'preact';
import { html } from 'htm/preact';
render(html`<a href="/">Hello!</a>`, document.body);
Enter fullscreen mode Exit fullscreen mode

What's nice, it's that you can use it with any frameworks.
For example in Mithril :

 const html = htm.bind(m);

 const Ciao = function ({attrs}) {
   return {view: () =>  html`<h1>Hello ${attrs.name}</h1>`}
 }
 m.render(app, m(Ciao, {name: "Raph"}))
Enter fullscreen mode Exit fullscreen mode

In React :

import ReactDOM from 'react-dom';
import { html } from 'htm/react';
ReactDOM.render(html`<a href="/">Hello!</a>`, document.body);
Enter fullscreen mode Exit fullscreen mode

As you can see, in order display the component, you have to pass it to a 'render' function, specific to the framework used.

Wouldn't it be nice if we could do ? :

let HelloWorld = html`<h1>Hello</h1>`
document.body.append(HelloWorld)
Enter fullscreen mode Exit fullscreen mode

It turns out it's indeed possible HTML to Dom Element :

import { html } from "sinuous"

let HelloWorld = html`<h1>Hello</h1>`
HelloWorld.style.color = "red";
document.body.append(HelloWorld)
Enter fullscreen mode Exit fullscreen mode

Here the 'html' function returns a real DOM element.
Thanks to Sinuous

There are really many advantages in doing so.
It is not unlike the nice library DML;

Here is another example IonicSinuous:

const { html, observable, map } = sinuous;

const Users = observable([]);

function Services() {
  async function fetchRandomUsers() {
    const response = 
        await fetch('https://randomuser.me/api/?results=10');
    const data = await response.json();
    Users(data.results);
  }
  return {
    fetchRandomUsers,
  };
}

const User = (user, index) => {
  let userView =  html`
      <ion-item style="display:none;">
        <ion-avatar style="margin-right:10px">
          <ion-img src=${user.picture.thumbnail}></ion-img>
        </ion-avatar>
        <ion-label>
          ${user.name.first} ${user.name.last}
        </ion-label>
      </ion-item>
    `;
  setTimeout(() => userView.style.display = "block" , 10 * index + 10)
  return  userView;
};


const App = () => {
  const svc = Services();
  return html`
    <ion-content style="text-align:center">
      <ion-button
        onclick=${svc.fetchRandomUsers}
      >
        Fetch Users
      </ion-button>
      <ion-list>
        ${() => Users().map((user,index) => User(user, index))}
      </ion-list>
    </ion-content>
  `;
};

document.body.appendChild(App());

Enter fullscreen mode Exit fullscreen mode
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .