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

solid-tag

v0.0.4

Published

Browser-friendly JSX to @solidjs/html tagged-template source transformer

Readme

Monorepo: See the workspace root README.md, ARCHITECTURE.md and docs/CONFORMANCE.md for shared playwright test orchestration. This package remains independently publishable.

solid-tag

solid-tag lowers ordinary JSX source into the tagged-template syntax consumed by Solid 2's @solidjs/html runtime.

It is intentionally not the normal Solid JSX DOM compiler and it does not depend on Solid.

ordinary JSX source
      ↓
   solid-tag
      ↓
JavaScript + html`...`
      ↓
@solidjs/html at runtime

Install

npm install solid-tag

Optional Solid 1.x entry point (since 0.0.4)

The default solid-tag import continues to target Solid 2 (@solidjs/html). Solid 1.x has a completely separate transformer package, [solid-tag-1], which can be accessed directly or through this small convenience re-export:

# Solid 2 only: no Solid 1 dependency installed
npm install solid-tag

# Only Solid 1: no need for solid-tag
npm install solid-tag-1

# Optional convenience path through solid-tag
npm install solid-tag solid-tag-1
// Solid 2 (unchanged)
import { transformJSX as transformSolid2 } from "solid-tag";

// Solid 1 (independent implementation)
import { transform } from "solid-tag-1";
// Or, with both packages installed:
import { transform as transformSolid1 } from "solid-tag/solid1";

const { code } = transformSolid1('export default () => <div>Hello</div>', {
  filename: 'App.jsx'
});
// Solid 1 output uses `solid-js/html`, not `@solidjs/html`.

The /solid1 path contains only an ES module and TypeScript re-export of solid-tag-1. solid-tag declares solid-tag-1 as an optional peer; it does not bundle or automatically install the Solid 1 compiler. Importing the subpath without installing solid-tag-1 produces a missing-module error.

The two transformers have distinct APIs: for example, Solid 1's transformJSX() returns a string, whereas Solid 2's transformJSX() returns a result object. Do not interchange their API assumptions. Use the published solid-tag-1 README for Solid 1 options, playground, and conformance tests.

solid-tag/solid1 is a convenience surface only. The canonical package for BMR's future Solid 1 framework adapter is solid-tag-1 itself; this avoids accidentally coupling its provider to Solid 2.

Basic use

import { transformJSX } from "solid-tag";

const result = transformJSX(`
  function App(props) {
    return <button onClick={props.onClick}>{props.label}</button>;
  }
`);

console.log(result.code);

The result contains tagged syntax such as:

function App(props) {
  return html`<button onClick=${props.onClick}>${() => (props.label)}</button>`;
}

transformJSX() only rewrites JSX. It does not add an @solidjs/html import.

Module helper

transformModule() can optionally add the @solidjs/html runtime import to transformed module source:

import { transformModule } from "solid-tag";

const result = transformModule(source);

// result.code begins with:
// import html from "@solidjs/html";

You can disable or customize that behavior:

transformModule(source, {
  injectHtmlImport: false,
  tag: "tpl",
  htmlImportSource: "@solidjs/html"
});

API

transformJSX(source, options?)

Returns:

{
  code: string;
  diagnostics: Array<{
    severity: string;
    message: string;
    start: number | null;
    end: number | null;
  }>;
  changed: boolean;
}

Options currently include:

{
  tag?: string; // default "html"
  parseOptions?: Record<string, unknown>;
  wrapDynamicDomExpressions?: boolean;
  wrapComponentProps?: boolean;
  rewriteIdentifierRefs?: boolean;
}

transformModule(source, options?)

Same result as transformJSX, with optional @solidjs/html import injection.

parseJSX(source, options?)

Exposes the built-in Acorn + acorn-jsx parser.

transformAst(source, ast, options?)

Parser-independent lower-level transform. The AST must be ESTree-compatible and provide start/end offsets on JSX/expression nodes.

createTransformer(parse, options?)

Build a transformer around another parser.

Component callback props

Event-looking props on components remain component callback values rather than DOM events.

<Editor onChange={value => save(value)} />

Because @solidjs/html uses function arity to distinguish callback values from getter holes, a zero-argument inline component callback is rewritten with one ignored argument. Callbacks that already accept one or more arguments are preserved directly.

Refs

@solidjs/html accepts callback-form refs, while Solid JSX allows both writable variable refs and callback refs. solid-tag adapts identifier refs at runtime so both forms work:

let element;
<div ref={element} />

assigns the rendered element to element, while:

const mount = element => console.log(element);
<div ref={mount} />

invokes mount(element) without attempting to assign to the const binding. Inline and forwarded callback expressions are preserved directly.

Current scope

The initial lowering handles:

  • native JSX elements
  • components and member components
  • dynamic DOM attributes and children
  • component props
  • DOM and component events
  • variable and callback refs lowered to callback-form refs
  • spreads
  • fragments
  • nested JSX in expressions
  • For-style render callbacks
  • JSX text whitespace normalization

Current limitations:

  • the built-in parser accepts JavaScript + JSX, not TypeScript/TSX source strings
  • source maps are not generated yet
  • directives and special DOM namespaces still need a larger runtime-conformance matrix
  • this is an early compatibility layer, not yet a complete replacement for all babel-preset-solid JSX semantics

Component event callback arity

solid-tag distinguishes event handlers from ordinary reactive attribute expressions so they are not accidentally turned into a function that returns another function.

For component on* props, @solidjs/html uses function arity to distinguish callbacks from getter-shaped values. Inline callbacks that already accept an argument are preserved. Zero-argument callbacks are adapted to accept an ignored event argument. Identifier/member/dynamic event expressions are evaluated once; non-functions and functions with existing arity are preserved exactly, while only zero-argument functions receive a forwarding arity adapter.