A virtual DOM library with focus on simplicity, modularity, powerful features and performance.
—
Snabbdom provides comprehensive JSX support with factory functions and TypeScript definitions for React-style development patterns.
Creates virtual nodes from JSX syntax, supporting both HTML elements and function components.
/**
* JSX factory function for creating virtual nodes
* @param tag - HTML tag name or function component
* @param data - Virtual node data (props, attrs, etc.)
* @param children - Child elements
* @returns Virtual node
*/
function jsx(
tag: string | FunctionComponent,
data: VNodeData | null,
...children: JsxVNodeChildren[]
): VNode;
type FunctionComponent = (
props: { [prop: string]: any } | null,
children?: VNode[]
) => VNode;Creates document fragments for grouping elements without wrapper elements (experimental).
/**
* JSX Fragment component for grouping elements
* @param data - Optional data object with key
* @param children - Child elements to group
* @returns Virtual node representing a fragment
*/
function Fragment(
data: { key?: Key } | null,
...children: JsxVNodeChildren[]
): VNode;Add the following to your tsconfig.json:
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "jsx",
"jsxFragmentFactory": "Fragment"
}
}Usage Example:
import { Fragment, jsx, VNode, init, classModule, styleModule } from "snabbdom";
const patch = init([classModule, styleModule]);
// Simple JSX elements
const greeting: VNode = <h1>Hello, World!</h1>;
// Elements with props and children
const button: VNode = (
<button
class={{ primary: true, large: false }}
on={{ click: () => console.log("clicked") }}
>
Click me
</button>
);
// Complex JSX structure
const app: VNode = (
<div class="app">
<header>
<h1>My Application</h1>
</header>
<main>
<p>Welcome to Snabbdom with JSX!</p>
{button}
</main>
</div>
);
// JSX Fragments (experimental)
const fragmentExample: VNode = (
<>
<p>First paragraph</p>
<p>Second paragraph</p>
</>
);For JavaScript projects using Babel, add the following to your Babel configuration:
{
"plugins": [
[
"@babel/plugin-transform-react-jsx",
{
"pragma": "jsx",
"pragmaFrag": "Fragment"
}
]
]
}Usage Example:
import { Fragment, jsx } from "snabbdom";
const component = (
<div>
<span>I was created with JSX</span>
</div>
);
const fragmentComponent = (
<>
<span>JSX fragments</span>
are experimentally supported
</>
);Create reusable function components that receive props and return virtual nodes.
type FunctionComponent = (
props: { [prop: string]: any } | null,
children?: VNode[]
) => VNode;Usage Examples:
import { jsx, VNode, h } from "snabbdom";
// Simple function component
function Greeting(props: { name: string } | null): VNode {
return <h1>Hello, {props?.name || "World"}!</h1>;
}
// Function component with children
function Card(
props: { title: string; className?: string } | null,
children?: VNode[]
): VNode {
return (
<div class={props?.className || "card"}>
<h2>{props?.title}</h2>
<div class="card-body">
{children}
</div>
</div>
);
}
// Using function components
const app: VNode = (
<div>
<Greeting name="Snabbdom" />
<Card title="Welcome" className="welcome-card">
<p>This is card content</p>
<button>Action</button>
</Card>
</div>
);JSX supports conditional rendering with boolean expressions.
import { jsx, VNode } from "snabbdom";
function ConditionalExample(props: { showMessage: boolean } | null): VNode {
return (
<div>
<h1>Conditional Rendering</h1>
{props?.showMessage && <p>This message is conditionally shown</p>}
{props?.showMessage ? <p>Condition is true</p> : <p>Condition is false</p>}
</div>
);
}Map over arrays to create lists of elements.
import { jsx, VNode } from "snabbdom";
interface User {
id: number;
name: string;
email: string;
}
function UserList(props: { users: User[] } | null): VNode {
const users = props?.users || [];
return (
<ul class="user-list">
{users.map(user => (
<li key={user.id} class="user-item">
<strong>{user.name}</strong> - {user.email}
</li>
))}
</ul>
);
}
// Usage
const users: User[] = [
{ id: 1, name: "Alice", email: "alice@example.com" },
{ id: 2, name: "Bob", email: "bob@example.com" }
];
const userListVNode = <UserList users={users} />;type JsxVNodeChild = VNode | string | number | boolean | undefined | null;
type JsxVNodeChildren = ArrayOrElement<JsxVNodeChild>;
type ArrayOrElement<T> = T | T[];
namespace jsx {
type Element = VNode;
type VNodeProps<T> = ElementProperties<T> & Props;
type HtmlElements = {
[Property in keyof HTMLElementTagNameMap]: VNodeData<
VNodeProps<HTMLElementTagNameMap[Property]>
>;
};
interface IntrinsicElements extends HtmlElements {
[elemName: string]: VNodeData;
}
}Install with Tessl CLI
npx tessl i tessl/npm-snabbdom