Hyperscript - the hidden language of React
Tags: react, javascript, webdev, tutorial
Published: 2021-12-29 18:38:31

## JSX is the starting point
React uses JSX to make things easier for the developers. So when you write something like this.
```jsx
<div id="foo">
  Hello!
</div>
```
Babel with a react preset transforms it to this.
```js
React.createElement("div", {
  id: "foo"
}, "Hello!");
```
Check out this example in [Babel REPL](https://babeljs.io/repl#?browsers=defaults%2C%20ie%206&build=&builtIns=false&corejs=3.6&spec=false&loose=false&code_lz=MYewdgzgLgBAJgSwG4wLwwDyJQuqBEAZiCPgHwASApgDY0gCEGA9NmUA&debug=false&forceAllTransforms=true&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=true&timeTravel=false&sourceType=module&lineWrap=true&presets=env%2Creact&prettier=false&targets=&version=7.16.6&externalPlugins=&assumptions=%7B%7D).
`React.createElement` is a function that creates a virtual node.
It's a well-known fact, and you probably already know it. So what's the point?
## Preact way
If you've used Preact before, you may notice it has [an unobvious export](https://github.com/preactjs/preact/blob/master/src/index.js#L4) in its source code.
```js
export {
		createElement,
		createElement as h,
} from './create-element';
```
To make things clear, the `createElement` function from Preact serves the same needs as `React.createElement`. So the question is, why is it exported as `h` as well?

The reason is dead simple. It's exported as `h` because it's [a hypescript function](https://github.com/hyperhype/hyperscript/tree/9237f590f3bc82b841ba6e7c4df946f21dff0045). 
So what exactly is hypescript?

## Hyperscript is the key
Hypescript is a kind of language to create HyperText with JavaScript and was started by Dominic Tarr in 2012. He was inspired by [markaby](https://github.com/markaby/markaby), the "short bit of code" to write HTML in pure Ruby.
Markaby allows doing things like that.
```ruby
require 'markaby'

mab = Markaby::Builder.new
mab.html do
  head { title "Boats.com" }
  body do
    h1 "Boats.com has great deals"
    ul do
      li "$49 for a canoe"
      li "$39 for a raft"
      li "$29 for a huge boot that floats and can fit 5 people"
    end
  end
end
puts mab.to_s
```
And the `h` function allows doing essentially the same thing, but with different syntax.
```js
h = require("hyperscript")

h("div#foo", "Hello!")
```
It also supports nesting and CSS properties.
```js
h = require("hyperscript")

h("div#foo", 
  h("h1", "Hello from H1!", { style: { 'color': 'coral' } })
)
```
Check out [an interactive demo](https://hyperhype.github.io/hyperscript/) to see how it works.

## Get your hands dirty
Now when we know what the `h` function does and why we need it, let's write our own version of it. Complete example can be found on [codesanbox](https://codesandbox.io/s/h-edxqp).

First, let's make up a `render` function, that creates real DOM elements from our virtual nodes.
```js
const render = ({type, children, props}) => {
  const element = document.createElement(type);

  if (props) {
    for (const prop in props) {
      element.setAttribute(prop, props[prop]);
    }
  }

  if (children) {
    if (Array.isArray(children)) {
      children.forEach(child => {
        if (typeof child === 'string') {
          element.innerText = child;
        } else {
          element.appendChild(render(child));
        }
      })
    } else if (typeof children === 'string') {
      element.innerText = children;
    } else {
      element.appendChild(render(children));
    }
  }

  return element;
}
```

Than, let's create the `h` function.
```js
const h = (type, children, props) => {
  let handledType = typeof type === 'string' ? type : 'div';

  return {
    type: handledType,
    props,
    children
  }
}
```

Finally, let's create an actual content with our `h` function, render it with our `render` function and mount the result to the DOM.
```js
const div = render(
  h('div',
    [ 
      h('h1', 'Hello!', { id: 'foo' }),
      h('h2', 'World!', { class: 'bar' })
    ],
  )
);

document.querySelector('#app').appendChild(div);
```