solidjs/solid
solid-js/h and solid-js/html
Active contributors: Ryan Carniato
Two compiler-free entry points for using Solid without JSX or a build step. solid-js/h exposes a HyperScript factory; solid-js/html exposes a tagged-template literal. Both produce the same DOM the JSX compiler would, at the cost of a slightly larger runtime that cannot be tree-shaken.
Purpose
The default story for Solid is JSX + babel-preset-solid. These two entries cover the cases where that is not available:
- Running Solid in a
<script>tag with no build (CDN usage, REPLs). - Embedding in environments that already standardise on a non-JSX templating shape (
htm,lit-htmlstyle). - Authors who simply prefer not to use JSX.
Both packages are thin wrappers — the bulk of the work is done in the hyper-dom-expressions and lit-dom-expressions sibling libraries.
Directory layout
packages/solid/
├── h/
│ ├── package.json # ./h export selector
│ ├── tsconfig.json
│ ├── README.md # API + caveats
│ └── src/
│ ├── index.ts # createHyperScript wiring
│ └── hyperscript.ts # imported types from hyper-dom-expressions
└── html/
├── package.json # ./html export selector
├── tsconfig.json
├── README.md
└── src/
├── index.ts # createHTML wiring
└── lit.ts # imported types from lit-dom-expressions
packages/solid/h/jsx-runtime/ # JSX runtime entry for HyperScript-backed JSX
└── src/
└── index.tsThe h/jsx-runtime/ entry is what enables "jsxImportSource": "solid-js/h" in tsconfig.json for projects that want to use TypeScript's JSX with HyperScript output (for example, Solid in a non-Babel pipeline).
Key abstractions
solid-js/h
| Symbol | Source | Description |
|---|---|---|
h(tag, props?, ...children) |
packages/solid/h/src/index.ts |
The HyperScript factory. Three call shapes: element name + props + children, element name + children, component + props/children. |
HyperScript (type) |
hyper-dom-expressions (re-exported via hyperscript.ts) |
The functional surface of h. |
Implementation:
import {
assign,
createComponent,
dynamicProperty,
insert,
spread,
SVGElements,
} from 'solid-js/web';
import { createHyperScript } from './hyperscript.js';
const h: HyperScript = createHyperScript({
spread,
assign,
insert,
createComponent,
dynamicProperty,
SVGElements,
});
export default h;createHyperScript (from hyper-dom-expressions) accepts the runtime primitive bag and returns the h factory. The actual element-creation logic lives there.
solid-js/html
| Symbol | Source | Description |
|---|---|---|
html`<button>${count}</button>` |
packages/solid/html/src/index.ts |
The tagged-template literal. ${} interpolates JS expressions; <//> closes a component. |
HTMLTag (type) |
lit-dom-expressions (re-exported via lit.ts) |
The signature of the html literal. |
Implementation:
import { createHTML } from "./lit.js";
import {
effect, style, insert, untrack, spread, createComponent, delegateEvents,
classList, dynamicProperty, mergeProps, setAttribute, setAttributeNS,
addEventListener, Aliases, getPropAlias, Properties, ChildProperties,
DelegatedEvents, SVGElements, SVGNamespace
} from "solid-js/web";
const html: HTMLTag = createHTML({ effect, style, insert, ... });
export default html;Both factories take their primitives from solid-js/web (which itself re-exports them from dom-expressions). They depend on solid-js/web only — not on solid-js's reactive runtime directly.
How they differ from JSX
The READMEs at packages/solid/h/README.md and packages/solid/html/README.md enumerate the gotchas. Summary:
| Concern | JSX | h / html |
|---|---|---|
| Reactive expressions | Compiler wraps automatically | Must be wrapped in () => ... manually |
| Spreading props | <div {...props} /> |
h("div", mergeProps({class: "foo"}, props)) or template-literal ...${props} |
| Refs | ref={el => ...} or let myEl; <div ref={myEl} /> |
Only the callback form is supported |
| Fragments | <>...</> |
Plain arrays in h; multiple top-level elements work natively in html |
| Bundle size | Tree-shakeable runtime | Pulls in hyper-dom-expressions / lit-dom-expressions runtime, not tree-shakeable |
Key source files
| File | Purpose |
|---|---|
packages/solid/h/src/index.ts |
Wires createHyperScript to solid-js/web. |
packages/solid/h/src/hyperscript.ts |
Type re-exports for the HyperScript shape. |
packages/solid/h/jsx-runtime/src/index.ts |
JSX runtime entry — lets TypeScript's JSX transform target solid-js/h directly. |
packages/solid/html/src/index.ts |
Wires createHTML to solid-js/web. |
packages/solid/html/src/lit.ts |
Type re-exports for the HTMLTag shape. |
Integration points
- Both depend on
solid-js/web(Rollupexternal: ["solid-js/web"]). - Indirectly depend on
hyper-dom-expressions(workspace devDep) andlit-dom-expressions(workspace devDep) — the actual factories live there. - Used by the JSX-less playground builds and by
solid-elementprojects that want to author components in a script-tag context.
Entry points for modification
- Updating to a new
hyper-dom-expressionsversion: bump the workspace devDependency in the rootpackage.json. The Solid-side wiring inpackages/solid/h/src/index.tsrarely needs to change because the constructor accepts the runtime bag, not specific behaviours. - Adding a new operator (e.g. server-rendered tagged literal): add a parallel entry under
packages/solid/html/server/and wire it up inpackages/solid/rollup.config.js. As of today, the tagged literal is browser-only becauselit-dom-expressionsdoes not ship a server build.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.