HTM (Hyperscript Tagged Markup) npm

hyperscript tagged markup demo

`htm` is **JSX-like syntax in plain JavaScript** - no transpiler necessary. Develop with React/Preact directly in the browser, then compile `htm` away for production. It uses standard JavaScript [Tagged Templates] and works in [all modern browsers]. ## `htm` by the numbers: 🐣 **< 600 bytes** when used directly in the browser ⚛️ **< 500 bytes** when used with Preact _(thanks gzip 🌈)_ 🥚 **< 450 byte** `htm/mini` version 🏅 **0 bytes** if compiled using [babel-plugin-htm] ## Syntax: like JSX but also lit The syntax you write when using HTM is as close as possible to JSX: - Spread props: `
` - Self-closing tags: `
` - Components: `<${Foo}>` _(where `Foo` is a component reference)_ - Boolean attributes: `
` ## Improvements over JSX `htm` actually takes the JSX-style syntax a couple steps further! Here's some ergonomic features you get for free that aren't present in JSX: - **No transpiler necessary** - HTML's optional quotes: `
` - Component end-tags: `<${Footer}>footer content` - Syntax highlighting and language support via the [lit-html VSCode extension] and [vim-jsx-pretty plugin]. - Multiple root element (fragments): `
` - Support for HTML-style comments: `
` ## Installation `htm` is published to npm, and accessible via the unpkg.com CDN: **via npm:** ```js npm i htm ``` **hotlinking from unpkg:** _(no build tool needed!)_ ```js import htm from 'https://unpkg.com/htm?module' const html = htm.bind(React.createElement); ``` ```js // just want htm + preact in a single file? there's a highly-optimized version of that: import { html, render } from 'https://unpkg.com/htm/preact/standalone.module.js' ``` ## Usage If you're using Preact or React, we've included off-the-shelf bindings to make your life easier. They also have the added benefit of sharing a template cache across all modules. ```js import { render } from 'preact'; import { html } from 'htm/preact'; render(html`Hello!`, document.body); ``` Similarly, for React: ```js import ReactDOM from 'react-dom'; import { html } from 'htm/react'; ReactDOM.render(html`Hello!`, document.body); ``` ### Advanced Usage Since `htm` is a generic library, we need to tell it what to "compile" our templates to. You can bind `htm` to any function of the form `h(type, props, ...children)` _([hyperscript])_. This function can return anything - `htm` never looks at the return value. Here's an example `h()` function that returns tree nodes: ```js function h(type, props, ...children) { return { type, props, children }; } ``` To use our custom `h()` function, we need to create our own `html` tag function by binding `htm` to our `h()` function: ```js import htm from 'htm'; const html = htm.bind(h); ``` Now we have an `html()` template tag that can be used to produce objects in the format we created above. Here's the whole thing for clarity: ```js import htm from 'htm'; function h(type, props, ...children) { return { type, props, children }; } const html = htm.bind(h); console.log( html`

Hello world!

` ); // { // type: 'h1', // props: { id: 'hello' }, // children: ['Hello world!'] // } ``` If the template has multiple element at the root level the output is an array of `h` results: ```js console.log(html`

Hello

World!
`); // [ // { // type: 'h1', // props: { id: 'hello' }, // children: ['Hello'] // }, // { // type: 'div', // props: { class: 'world' }, // children: ['world!'] // } // ] ``` ## Example Curious to see what it all looks like? Here's a working app! It's a single HTML file, and there's no build or tooling. You can edit it with nano. ```html htm Demo ``` [⚡️ **See live version** ▶](https://htm-demo-preact.glitch.me/) [⚡️ **Try this on CodeSandbox** ▶](https://codesandbox.io/s/x7pmq32j6q) How nifty is that? Notice there's only one import - here we're using the prebuilt Preact integration since it's easier to import and a bit smaller. The same example works fine without the prebuilt version, just using two imports: ```js import { h, Component, render } from 'preact'; import htm from 'htm'; const html = htm.bind(h); render(html`<${App} page="All" />`, document.body); ``` ## Other Uses Since `htm` is designed to meet the same need as JSX, you can use it anywhere you'd use JSX. **Generate HTML using [vhtml]:** ```js import htm from 'htm'; import vhtml from 'vhtml'; const html = htm.bind(vhtml); console.log( html`

Hello world!

` ); // '

Hello world!

' ``` **Webpack configuration via [jsxobj]:** ([details here](https://webpack.js.org/configuration/configuration-languages/#babel-and-jsx)) _(never do this)_ ```js import htm from 'htm'; import jsxobj from 'jsxobj'; const html = htm.bind(jsxobj); console.log(html` `); // { // watch: true, // mode: 'production', // entry: { // path: 'src/index.js' // } // } ``` ## Demos & Examples - [Canadian Holidays](https://github.com/pcraig3/hols): A full app using HTM and Server-Side Rendering - [HTM SSR Example](https://github.com/timarney/htm-ssr-demo): Shows how to do SSR with HTM - [HTM + Preact SSR Demo](https://gist.github.com/developit/699c8d8f180a1e4eed58167f9c6711be) - [HTM + vhtml SSR Demo](https://gist.github.com/developit/ff925c3995b4a129b6b977bf7cd12ebd) ## Project Status The original goal for `htm` was to create a wrapper around Preact that felt natural for use untranspiled in the browser. I wanted to use Virtual DOM, but I wanted to eschew build tooling and use ES Modules directly. This meant giving up JSX, and the closest alternative was [Tagged Templates]. So, I wrote this library to patch up the differences between the two as much as possible. The technique turns out to be framework-agnostic, so it should work great with any library or renderer that works with JSX. `htm` is stable, fast, well-tested and ready for production use. [Tagged Templates]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates [lit-html]: https://github.com/Polymer/lit-html [babel-plugin-htm]: https://github.com/developit/htm/tree/master/packages/babel-plugin-htm [lit-html VSCode extension]: https://marketplace.visualstudio.com/items?itemName=bierner.lit-html [vim-jsx-pretty plugin]: https://github.com/MaxMEllon/vim-jsx-pretty [vhtml]: https://github.com/developit/vhtml [jsxobj]: https://github.com/developit/jsxobj [hyperscript]: https://github.com/hyperhype/hyperscript [all modern browsers]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Browser_compatibility