Skip to main content
Creates a virtual node (VNode) representing a DOM element or component. This is Preact’s hyperscript function, commonly used as the JSX pragma.

Signature

// For HTML elements
function h<P extends HTMLAttributes<T>, T extends HTMLElement>(
  type: keyof JSXInternal.IntrinsicElements,
  props: (ClassAttributes<T> & P) | null,
  ...children: ComponentChildren[]
): VNode<ClassAttributes<T> & P>

// For components
function h<P>(
  type: ComponentType<P> | string,
  props: (Attributes & P) | null,
  ...children: ComponentChildren[]
): VNode<P>

Parameters

type
string | ComponentType<P>
required
The element type. Can be:
  • A string for HTML/SVG elements (e.g., 'div', 'span', 'svg')
  • A function component
  • A class component
props
object | null
An object containing the element’s properties/attributes. Special props:
  • key: Unique identifier for reconciliation
  • ref: Reference to the DOM node or component instance
  • All other props are passed to the component or set as attributes
children
ComponentChildren
Child elements. Can be:
  • VNodes created with h()
  • Strings or numbers (rendered as text)
  • Arrays of children
  • null, undefined, or booleans (not rendered)

Return Value

Returns a VNode<P> object representing the virtual DOM node.

Description

h is Preact’s hyperscript function, used to create virtual DOM nodes. It’s the target function for JSX transformations and can also be called directly. The function is an alias for createElement and has identical behavior. The name h is shorter and commonly used in hyperscript-style code.

Usage Examples

JSX Pragma

/** @jsx h */
import { h } from 'preact';

function Button() {
  return <button>Click me</button>;
}

// JSX transforms to:
// h('button', null, 'Click me')

Direct Function Calls

import { h } from 'preact';

// Create a simple element
const element = h('div', { class: 'container' }, 'Hello World');

// Create nested elements
const nested = h('div', null,
  h('h1', null, 'Title'),
  h('p', null, 'Paragraph')
);

With Props and Children

import { h } from 'preact';

const button = h(
  'button',
  {
    class: 'btn',
    onClick: () => console.log('Clicked!'),
    disabled: false
  },
  'Click me'
);

Creating Component VNodes

import { h } from 'preact';

function Greeting({ name }) {
  return h('div', null, `Hello, ${name}!`);
}

const vnode = h(Greeting, { name: 'World' });

With Key and Ref

import { h, createRef } from 'preact';

const inputRef = createRef();

const input = h('input', {
  key: 'my-input',
  ref: inputRef,
  type: 'text',
  placeholder: 'Enter text...'
});

Multiple Children

import { h } from 'preact';

const list = h('ul', null,
  h('li', { key: '1' }, 'Item 1'),
  h('li', { key: '2' }, 'Item 2'),
  h('li', { key: '3' }, 'Item 3')
);

Arrays of Children

import { h } from 'preact';

const items = ['Apple', 'Banana', 'Cherry'];

const list = h('ul', null,
  items.map((item, i) => h('li', { key: i }, item))
);

Implementation Details

The h function is implemented in src/create-element.js:16 and shares the same implementation as createElement. The function:
  1. Normalizes props by extracting key and ref
  2. Collects all children arguments (supports variadic arguments)
  3. Calls internal createVNode to create the VNode object
export function createElement(type, props, children) {
  let normalizedProps = {},
    key,
    ref,
    i;
  for (i in props) {
    if (i == 'key') key = props[i];
    else if (i == 'ref' && typeof type != 'function') ref = props[i];
    else normalizedProps[i] = props[i];
  }

  if (arguments.length > 2) {
    normalizedProps.children =
      arguments.length > 3 ? slice.call(arguments, 2) : children;
  }

  return createVNode(type, normalizedProps, key, ref, NULL);
}

Special Props

key

Used by the diffing algorithm to identify elements across renders:
const items = data.map(item =>
  h('div', { key: item.id }, item.name)
);

ref

Provides access to the underlying DOM node:
import { h, createRef } from 'preact';

const myRef = createRef();
const element = h('div', { ref: myRef });

// After render: myRef.current === DOM node

dangerouslySetInnerHTML

Sets raw HTML content (use with caution):
const html = h('div', {
  dangerouslySetInnerHTML: { __html: '<strong>Bold</strong>' }
});

JSX Configuration

Configure your JSX transform to use h: TypeScript (tsconfig.json)
{
  "compilerOptions": {
    "jsx": "react",
    "jsxFactory": "h",
    "jsxFragmentFactory": "Fragment"
  }
}
Babel (.babelrc)
{
  "plugins": [
    ["@babel/plugin-transform-react-jsx", {
      "pragma": "h",
      "pragmaFrag": "Fragment"
    }]
  ]
}

Build docs developers (and LLMs) love