Transforms arrays into virtual DOM trees
Find h
a bit repetitive? Not a huge fan of JSX? Love LISP? Code as data and data as code?
This is a tiny recursive factory function that allows you to write terse, declarative representations of virtual DOM trees. It does not try mimic HTML or JSON syntax but instead a series of nested arrays to represent user interfaces.
const tree = h('x', 'y', 'z')
(
['main', [
['h1', 'Hello World'],
['input', { type: 'range' }],
['button', { onclick: console.log }, 'Log Event'],
]]
)
The above call to h
returns a virtual DOM tree with named attributes that respect the provided schema. Expected output here, would be of the shape { x: 'main', y: {}, z: [...] }
. A tree like this can be passed as a node to patch, diff and render algorithms exposed by libraries like Hyperapp, Ultradom or Preact.
- Hyperapp / Ultradom / Preact:
h('nodeName','attributes','children')
A call to h(x,y,z)
returns a build function that expects a node of type [0,1,2]
where:
- Index
0
contains astring
used as the elements tag name (required) - Index
1
contains anobject
containing element attributes (optional) - Index
2
contains anstring|array
of content or children (optional)
Children are flattened and falsey children are excluded. Numbers passed as children get converted to strings.
npm i ijk
Here is a demo with Hyperapp and Preact.
import { h } from 'ijk'
const tree = h('nodeName', 'attributes', 'children')(
['main', [
['h1', 'Hello World'],
['input', { type: 'range' }],
['button', { onclick: console.log }, 'Log Event'],
['ul', [
['li', 1],
['li', 2],
['li', 3]
]],
false && ['span', 'Hidden']
]]
)
ijk is essentially h
but with optional props and you only have to call h
once; not every time you want to represent an element in the DOM. This generally means less repetition and one less import in your view files.
const h =
h('main', {}, [
h('h1', {}, 'Hello World'),
h('input', { type: 'range' }),
h('button', { onclick: console.log }, 'Log Event'),
h('ul', {}, [
h('li', {}, 1),
h('li', {}, 2),
h('li', {}, 3),
]),
false && h('span', {}, 'Hidden')
])
The main advantages over using JSX is less repetition of tag names and no build step is required.
const jsx =
<main>
<h1>Hello World</h1>
<input type='range' />
<button onclick={ console.log }>Log Event</button>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
{false && <span>'Hidden'</span>}
</main>
Here is an example that takes advantage of most features and demonstrates components.
import { h } from 'ijk'
const Item = data => ['li', data]
const Article = ({ title, story, related }) => [
'article',
[
['h2', title],
['hr'],
['p', story],
related.map(Item),
]
]
const Main =
['main', [
['h1', 'Hello World'],
['input', { type: 'range' }],
['ul', [
['li', 1],
['li', 2],
['li', 3],
]],
['button', { onclick: console.log }, 'Log Event'],
false && ['span', 'Hidden'],
Article({
title: 'Some News',
story: 'lorem ipsum dolor sit amet',
related: [4,5],
})
]]
const tree = h('nodeName', 'attributes', 'children')(Main)