Transforms arrays into virtual dom trees; a terse alternative to JSX and h
Clone or download
lukejacksonn Merge pull request #22 from futurist/master
reuse inner function when recursive
Latest commit cd8b897 Jul 10, 2018


Transforms arrays into virtual DOM trees

Build Status codecov

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' }],
    ['input', { 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 a string used as the elements tag name (required)
  • Index 1 contains an object containing element attributes (optional)
  • Index 2 contains an string|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 =
    <h1>Hello World</h1>
    <input type='range' />
    <button onclick={ console.log }>Log Event</button>
    {false && <span>'Hidden'</span>}


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 }) => [
    ['h2', title],
    ['p', story],,

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'],
      title: 'Some News',
      story: 'lorem ipsum dolor sit amet',
      related: [4,5],

const tree = h('nodeName', 'attributes', 'children')(Main)