hyperlit
lets you declare your hyperapp views in a html-like fashion, similar to JSX. Unlike JSX you don't need a build-step and babel config to do it -- it happens run-time in your browser. It's quite small – ca 0.6kb.
Here's Hyperapp's "Quickstart" example using hyperlit:
<!DOCTYPE html>
<html lang="en">
<head>
<script type="module">
import { app } from 'https://unpkg.com/hyperapp'
import html from 'https://unpkg.com/hyperlit'
app({
init: 0,
view: state => html`
<main>
<h1>${state}</h1>
<button onclick=${state => state - 1}>-</button>
<button onclick=${state => state + 1}>+</button>
</main>`,
node: document.getElementById('app')
})
</script>
</head>
<body>
<main id="app"></main>
</body>
</html>
In the following instructions I will just focus on how hyperlit replaces Hyperapp's h
function. For actually making working apps with this, familiarity with Hyperapp is assumed.
In projects where you do bundle your app up, install hyperlit using:
npm i hyperlit
Note that hyperapp is a peer-dependency which you'll also need to have installed.
Once installed, you can import hyperlit
wherever you declare views:
import html from 'hyperlit'
If you prefer not to use npm, you can use client side imports directly like this:
import html from 'https://unpkg.com/hyperlit'
Hyperlit replaces hyperapp's built-in h
, allowing you to write:
html`
<div class="big">
<h1>Title</h1>
<p class="aligned">
Content 1 <br />
Content 2
</p>
</div>`
instead of:
h('div', { class: 'big' }, [
h('h1', {}, text('Title')),
h('p', { class: 'aligned' }, [
text('Content 1'),
h('br', {}),
text('Content 2')
]),
])
If you have non-string props you want to add to your vnodes, or values kept in variables, use the ${val}
syntax to
inject them:
const foo = 32
const node = html`<p class=${{ bigger: foo > 30 }}>...</p>`
If you have a bunch of props you want to assign, you don't have to write them out individually, you can just:
const props = {class: 'bigger', id: 'a-1', key: 'a-1'}
const node = html`<p ${props}>...</p>`
(For compatibility with views you may have written using htm
, the ...${props}
syntax is also supported)
const name = 'Joe'
const greeting = html`<span>Hello ${name}!</span>`
results in h('span', {}, [text('Hello'), text('Joe'), text('!')])
.
Content can be a string or a vnode. Content can also be an array:
const names = ['Kim', 'Robin', 'Sam']
const person = name => html`<p>${name}</p>`
const list = html`
<div>
<p>Members:</p>
${names.map(person)}
</div>`
results in list
being equivalent to:
h('div', {}, [
h('p', {}, text('Members:')),
h('p', {}, text('Kim')),
h('p', {}, text('Robin')),
h('p', {}, text('Sam')),
])
Since hyperapp filters out falsy children, you can conditionally render some content:
const show = false
html`<p>Secret: ${show && 'I work for the CIA'}</p>`
Let's say you have this component:
const box = (props, content) => html`
<div class=${{ fancy: true, active: props.active }}>
<h1>${props.title}</h1>
${content}
</div>`
You could of course add it to a view in this way:
const view = html`
<main>
${box({ active: false, title: 'My bio' }, [
html`<p>Lorem ipsum</p>`,
html`<p>Dolor sit amet</p>`,
])}
</main>`
But hyperlit allows you to do it this way as well:
const view = html`
<main>
<${box} active=${false} title="My bio">
<p>Lorem ipsum</p>
<p>Dolor sit amet</p>
<//>
</main>`
For backwards compatibility with
htm
it is also possible to close components as</${box}>
This library is meant to let you write html-like views that can be rendered in the browser without any build step. Still, you might eventually perfer the parsing to be taken care of by your build-toolchain in order to get faster renders. Of course you should be able to do so! Simply add babel-plugin-hyperlit
to your babel config. In package.json
for example, it looks like this:
"babel": {
"plugins": ["hyperlit"]
}
With that, babel will make sure to transform all your hyperlit views into plain function calls, so the browser doesn't have to do any parsing.
If you use VS Code, install the lit-html to get highlighting and autocompletion that works well with hyperlit.
This project was inspired by Jason Miller's htm. I made it to have a similar solution that would work well with Hyperapp.
Thanks to Jorge Bucaran for making Hyperapp and for coming up with the name of this project!