jsx-for-web-components · npm 1.2.1 · work in progress
Components in TSX. Work in progress.
A small JSX factory and a component base class, so a custom element's markup can be written as JSX and compiled to plain DOM calls. Its README labels it WIP and this page keeps that label.
read this first
wip, by its own descriptionThe README's own summary is “WIP: A basic JSX factory for use in projects leveraging web components”. The last commit that changes code is the v1.2.1 tag, 2018-12-29; the newest commit, 2026-05-08, only adds a homepage link. The package is still on npm at 1.2.1, and the repository carries five Jest test files, but the toolchain it pins is from the same period — Jest 23, ts-jest 23, TSLint 5, TypeScript 3.2.
Treat it as a working sketch of an idea, not as a maintained framework. Nothing on this page has been compiled or run; the commands and files below are quoted from the README so you can judge the idea from its own example.
the surface
a factory and a base classh(type, props, ...children)- The pragma function the compiler calls for every JSX element. It returns a
plain object —
{ children, props, type }— and does no DOM work itself. JSXCustomElement- Extends
HTMLElement. A subclass setsstatic elementName, overridesrender(), and calls the inheritedstatic register(). The constructor builds atemplatefromrender()and callsattachShadow({ mode: 'open' });connectedCallback()clones the template into the shadow root. createElement(node)/createTemplate(node)- Turn that object tree into DOM.
node.typeis either a tag name or a function: tags becomedocument.createElement(), functions are constructed withReflect.construct()and rendered — theStatelessComponentpath. A comment insrc/types.tsrecords the gap: “TODO: Support classes for components”. renderToStaticMarkup(root)- Serialises an element to an HTML string: its tag, its attributes, then its shadow children, then its light children. It writes both sets inline; it does not emit a declarative shadow root.
src/register.ts mirrors the hydration library's helper: reject when
elementName is unset or window.customElements is missing,
otherwise define once and return customElements.whenDefined(). The
repository also vendors Polymer's Custom Elements v1 Reflect shim as
src/native-shim.ts, BSD licensed, with its original header intact.
install
yarn, then a compilerThe README's requirement is a single line: a compiler that can turn JSX into factory calls. Its install line, quoted:
yarn add jsx-for-web-components
Its worked example builds for the browser with TypeScript and Rollup, so it also installs the toolchain:
yarn add --dev typescript rollup rollup-plugin-node-resolve rollup-plugin-typescript2
The package itself declares one runtime dependency, csstype ^2.6.0, for
the CSS property types in its JSX attribute definitions. It publishes
lib/index.js and types/index.d.ts; npm run build
is tsc, and the repository's own tsconfig.json compiles
src/**/* to lib/ with strict on and DOM plus
ESNext libs.
Note what that tsconfig.json does not set: jsx and
jsxFactory. Those belong to the project consuming the library, and the
README's example supplies them itself.
one example, quoted
tsconfig, component, pageThe README's walkthrough, in three files. First the two compiler options that make the
factory work — classic JSX, with h as the factory:
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "h",
"moduleResolution": "node",
"target": "es2015"
}
}
Then the component, in src/index.tsx. The h import is
unused in the source but is what the compiled output calls:
import { h, JSXCustomElement } from "jsx-for-web-components";
class ExampleElement extends JSXCustomElement {
static elementName = "example-element";
public render() {
return <div id="testing">hello</div>;
}
}
ExampleElement.register();
And the page that uses it, in index.html:
<!DOCTYPE html>
<script src="/dist/index.js" defer></script>
<example-element></example-element>
After rollup -c rollup.config.js — the README also prints the Rollup config
it expects, an IIFE bundle of ./src/index.tsx into
./dist/index.js — the README says the page should load in a browser and
show the rendered work. That claim is the README's, not this site's: it was not
reproduced here.
how it differs
same pattern, no serverThe runtime pattern is the one the other two tools use, minus the server: a
template is filled from a render result, an open shadow root is attached in
the constructor, and the clone is appended on connect. There is no naming convention
shared with hydration — no template- id lookup and no
data-template placeholder — because this library renders its own elements
directly rather than adopting server markup.
Its renderToStaticMarkup() suggests a server-rendering path, but it
serialises an element's shadow children into the element's own light DOM. If you need
server output that a browser renders before JavaScript runs, nothing here produces it:
no file in this repository emits <template shadowrootmode>.
If you need a super call, the README's note is explicit: override
connectedCallback() and call super.connectedCallback(), or the
template never gets cloned into the shadow root.
where to go
the rest of the set-
The three tools
What the set does, and the one thing none of the three does.
-
Hydration in the browser
The maintained-in-2019 cousin of this library's base class.
-
Source on GitHub
src/, five Jest test files, and the Polymer shim. -
npm
jsx-for-web-components, latest 1.2.1.