npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@yukino.js/lit-jsx

v0.0.1

Published

A jsx runtime for lit

Readme

lit-jsx

Requires lit@latest (3.x); older Lit versions are not supported.

lit-jsx is a library that provides a convenient way to build Lit components using JSX syntax.

Installation

pnpm install @yukino.js/lit-jsx

Usage

To use lit-jsx simply import from @yukino.js/lit-jsx whatever you would otherwise import from lit. You also need to configure your bundler or transpiler to use lit-jsx for processing JSX, instead of the default. For example in TypeScript you would add something like this to your tsconfig.json:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "@yukino.js/lit-jsx"
  }
}

There is a similar mechanism for Babel where you would add something like this to your babel.config.js:

{
  "plugins": [
    [
      "@babel/plugin-transform-react-jsx",
      {
        "throwIfNamespace": false,
        "runtime": "automatic",
        "importSource": "@yukino.js/lit-jsx"
      }
    ]
  ]
}

Because Lit relies on legacy class-field semantics, also keep these options enabled: experimentalDecorators, emitDecoratorMetadata and useDefineForClassFields: false.

Rendering

JSX compiles to a Lit TemplateResult, so you can render it anywhere a Lit template is expected. The package ships a tiny createRoot wrapper for app-style mounting:

import { createRoot } from "@yukino.js/lit-jsx";

const root = createRoot(document.getElementById("app")!);
root.render(<App />);

Call root.render(...) again to update (lit-html diffs efficiently), and root.unmount() to clear the container.

Components

Functional components are plain functions that return JSX:

const Greeting = ({ name }: { name: string }) => <div>hi {name}</div>;

Custom elements are declared with LitElement and the customElement decorator exported from this package (it also records the tag name so the JSX runtime can render class references without instantiating them):

import { LitElement, customElement, property } from "@yukino.js/lit-jsx";

@customElement("my-greeting")
export class MyGreeting extends LitElement {
  @property() name = "";

  render() {
    return <h1>hello {this.name}</h1>;
  }
}

// Later, in any JSX — props arrive as element properties:
<my-greeting name="world" />;

Props

Prop handling follows React conventions where it makes sense and Lit/web-platform conventions where those differ:

  • onXxx props become real DOM event listeners on native tags (onClick → click, plus the full modern event surface — onWheel, onTouchEnd, composition, animation, transition events, etc.).
  • onXxx props on your own custom elements are not auto-bound: they are forwarded as properties, so the element decides what a prop named onClick means. The usual web-components pattern applies — dispatch a bubbling CustomEvent and listen for it on the parent.
  • className (or class) sets the class, style takes a camelCase style object (Lit's styleMap), and ref accepts Lit's ref objects or callbacks.
  • Hyphenated props (data-*, aria-*, …) become attributes; everything else is assigned as a DOM property — even when undefined, so reactive properties reset like you'd expect in Lit.
  • false, null and undefined children render nothing, just like React ({cond && <div />} is safe).
  • key is accepted for React familiarity but unused — Lit's diffing has no key semantics.

Custom Elements

lit-jsx allows you to customize what should be rendered for each tag name. For example, if you want JSX <button /> to result in <my-custom-button />, you would pass an override in your registry.

Here's how you would do that:

import { assignElements, resetElements } from "@yukino.js/lit-jsx";

// Define your custom elements
const customElements = {
  button: "my-custom-button",
  // Add more custom elements as needed
};

// Assign your custom elements
assignElements(customElements);

// Later, if you want to reset to the default elements
resetElements();

Override values can be plain strings (wrapped internally with Lit's unsafeStatic) or Lit static values such as literalmy-button``. You can also override the default mapping that unknown tags fall back to (by default, <div>).

And why in the world would I want to do that?

The original motivation behind this jsx-runtime was for a WebXR UI framework I was working on. In WebXR, any UI you make has to be rendered using Canvas/webgl which is as fun as it sounds so I wanted to be able to define UI components using HTML syntax. My basic idea was to create webgl/three-js versions of each HTML element and then configure lit-jsx so that whenever the JSX called for say, a "button" to be rendered, the webgl equivalent would be rendered instead.

I got a fair amount of it working including divs, images, text, overflow management, scroll bars, flex-box, border-radii, background colors, etc.

Development

This package lives in a pnpm workspace together with the demo app at the repository root.

pnpm test        # vitest + jsdom, tests in tests/
pnpm typecheck   # tsc --noEmit
pnpm build       # tsup — ESM + CJS + dts