Skip to main content
h() is Solar’s compact array notation for building vnode trees. Instead of nesting createElement calls, you write nested arrays — h() parses them into the same vnodes the reconciler uses. Because array literals are more concise than function call syntax, h() produces shorter render functions with fewer tokens, which is especially useful when an AI agent is generating or regenerating component trees. Registered component names resolve automatically, so you don’t need to import each component into every file that uses it.

Signature

h(node) → vnode | string | number
node
string | number | array
required
The node to convert. Primitive values — strings and numbers — are returned as-is. Arrays are parsed using the format described below.

Array format

When you pass an array, h() expects the following structure:
[type, props?, ...children]
type
string
required
The first element of the array. Either an HTML tag name (e.g., 'div', 'button') or the displayName of a registered component (e.g., 'Button', 'Card'). See Component name resolution below.
props
object
The second element of the array, if it is a plain object (not an array and not null). If the second element is an array or is omitted, h() treats it as the first child instead and uses {} as the props.
...children
string | number | array
All remaining elements after the optional props object. Each child is passed recursively through h(), so you can nest arrays to any depth.

Examples

import { h } from './solar/index.js'

h(['div', { class: 'container' },
  ['h1', {}, 'Hello'],
  ['p', {}, 'World'],
])

vs. createElement

The two forms produce identical vnodes. Choose the one that fits your context — createElement makes imports and data flow explicit; h() is more compact for large trees.
// createElement
createElement('div', { class: 'row' },
  createElement('span', {}, 'Name:'),
  Button({ label: 'Edit', onClick: onEdit }),
)

// h() — equivalent, more compact
h(['div', { class: 'row' },
  ['span', {}, 'Name:'],
  ['Button', { label: 'Edit', onClick: onEdit }],
])

Component name resolution

When the first element of an array is a string, h() checks the Solar registry:
  • If the name is registeredh() calls the component function with the provided props (and any children merged in). The result is the vnode that component’s render function returns.
  • If the name is not registeredh() falls through to createElement() and treats the string as an HTML tag name.
This means you must call registry.register(Component) before using the component’s name in an h() tree. The recommended pattern is to register each component at the bottom of its own file, so importing the file is enough to make the name available.
h() is a pure vnode factory — it produces the same static description of a UI tree as createElement. It does not manage state, schedule re-renders, or run lifecycle hooks. Components that use hooks such as useState or useResource must still be mounted with mountComponent() to enter Solar’s reactivity loop.