> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/preactjs/preact/llms.txt
> Use this file to discover all available pages before exploring further.

# createElement

> Create Preact virtual nodes (React-compatible API)

Creates a virtual node (VNode) representing a DOM element or component. This is Preact's React-compatible API for creating virtual DOM nodes.

## Signature

```typescript theme={null}
// For HTML elements
function createElement<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 createElement<P>(
  type: ComponentType<P> | string,
  props: (Attributes & P) | null,
  ...children: ComponentChildren[]
): VNode<P>
```

## Parameters

<ParamField path="type" 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
</ParamField>

<ParamField path="props" type="object | null">
  An object containing the element's properties/attributes. Special props:

  * `key`: Unique identifier for efficient reconciliation
  * `ref`: Reference to the DOM node or component instance
  * All other props are passed to the component or set as attributes
</ParamField>

<ParamField path="children" type="ComponentChildren">
  Child elements. Can be:

  * VNodes created with `createElement()`
  * Strings or numbers (rendered as text)
  * Arrays of children
  * `null`, `undefined`, or booleans (not rendered)
</ParamField>

## Return Value

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

## Description

`createElement` is Preact's React-compatible function for creating virtual DOM nodes. It's identical to the [`h`](/api/h) function but uses the React naming convention.

This function is the target of JSX transformations when using the React JSX pragma. It can also be called directly for creating virtual nodes programmatically.

## Implementation

The function is implemented in `src/create-element.js:16`:

```javascript theme={null}
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);
}
```

## Usage Examples

### JSX with React Pragma

```jsx theme={null}
import { createElement } from 'preact';

// JSX automatically transforms to createElement calls
function App() {
  return (
    <div className="app">
      <h1>Hello World</h1>
      <p>Welcome to Preact</p>
    </div>
  );
}

// Equivalent to:
// createElement('div', { className: 'app' },
//   createElement('h1', null, 'Hello World'),
//   createElement('p', null, 'Welcome to Preact')
// )
```

### Direct Function Calls

```javascript theme={null}
import { createElement } from 'preact';

// Create a simple element
const heading = createElement('h1', { className: 'title' }, 'Hello World');

// Create nested elements
const section = createElement('section', null,
  createElement('h2', null, 'Section Title'),
  createElement('p', null, 'Section content')
);
```

### Creating Components

```javascript theme={null}
import { createElement } from 'preact';

function Button({ label, onClick }) {
  return createElement('button', { onClick }, label);
}

function App() {
  return createElement(Button, {
    label: 'Click me',
    onClick: () => alert('Clicked!')
  });
}
```

### With Props and Event Handlers

```javascript theme={null}
import { createElement } from 'preact';

const input = createElement('input', {
  type: 'text',
  placeholder: 'Enter your name',
  value: 'John',
  onChange: (e) => console.log(e.target.value),
  onFocus: () => console.log('Focused'),
  className: 'text-input'
});
```

### Lists with Keys

```javascript theme={null}
import { createElement } from 'preact';

function TodoList({ todos }) {
  return createElement('ul', null,
    todos.map(todo =>
      createElement('li', { key: todo.id }, todo.text)
    )
  );
}
```

### Using Refs

```javascript theme={null}
import { createElement, createRef } from 'preact';
import { useEffect } from 'preact/hooks';

function AutoFocusInput() {
  const inputRef = createRef();
  
  useEffect(() => {
    inputRef.current.focus();
  }, []);
  
  return createElement('input', {
    ref: inputRef,
    type: 'text',
    placeholder: 'This will be focused'
  });
}
```

### Conditional Rendering

```javascript theme={null}
import { createElement } from 'preact';

function Greeting({ isLoggedIn, username }) {
  return createElement('div', null,
    isLoggedIn
      ? createElement('p', null, `Welcome back, ${username}!`)
      : createElement('p', null, 'Please log in')
  );
}
```

### Spreading Props

```javascript theme={null}
import { createElement } from 'preact';

function CustomInput(props) {
  // Spread props onto native input
  return createElement('input', {
    ...props,
    className: `custom-input ${props.className || ''}`
  });
}

const input = createElement(CustomInput, {
  type: 'email',
  placeholder: 'Email address',
  required: true
});
```

## Special Behaviors

### Key Prop

The `key` prop is extracted and not passed to the component:

```javascript theme={null}
// key is used internally for reconciliation
const item = createElement('div', { key: '123', id: 'item-123' });
// The component receives: { id: 'item-123' }
// The key is stored separately on the VNode
```

### Ref Prop

The `ref` prop is extracted for DOM elements but passed through for function components:

```javascript theme={null}
// For DOM elements - ref is extracted
const div = createElement('div', { ref: myRef });

// For function components - ref is passed as prop
function MyComponent({ ref }) {
  // ref is available as a prop
}
const component = createElement(MyComponent, { ref: myRef });
```

### Children Normalization

Children are automatically collected from all arguments after props:

```javascript theme={null}
// Single child
createElement('div', null, 'text');
// props.children = 'text'

// Multiple children
createElement('div', null, 'text', createElement('span'));
// props.children = ['text', VNode]

// Children as prop (takes precedence)
createElement('div', { children: 'from props' }, 'from args');
// props.children = 'from args' (arguments override props)
```

## JSX Configuration

Configure JSX to use `createElement` with React-compatible settings:

**TypeScript (tsconfig.json)**

```json theme={null}
{
  "compilerOptions": {
    "jsx": "react",
    "jsxFactory": "createElement",
    "jsxFragmentFactory": "Fragment"
  }
}
```

**Babel (.babelrc)**

```json theme={null}
{
  "plugins": [
    ["@babel/plugin-transform-react-jsx", {
      "pragma": "createElement",
      "pragmaFrag": "Fragment"
    }]
  ]
}
```

**Or use automatic runtime (React 17+)**

```json theme={null}
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact"
  }
}
```

## Performance Notes

* The function normalizes props efficiently by only copying non-special props
* Variadic children arguments are only allocated when multiple children exist
* VNode creation is optimized with object shape consistency

## Related APIs

* [`h`](/api/h) - Identical function with hyperscript naming
* [`Fragment`](/api/fragment) - Render multiple children without a wrapper
* [`cloneElement`](/api/clone-element) - Clone and modify existing VNodes
* [`render`](/api/render) - Render VNodes to the DOM
