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

@fluixi/jsx

v1.0.0-alpha.57

Published

JSX runtime types and factory for Fluixi — fine-grained, no virtual DOM.

Downloads

481

Readme

@fluixi/jsx

A fine-grained JSX runtime — native JSX and lit-html templates, no virtual DOM.

License: MIT TypeScript npm JSX


A comprehensive JSX runtime with fine-grained reactivity, inspired by SolidJS. This package provides a modern JSX implementation that supports both native JSX and lit-html templates, with seamless integration with signal and store systems for optimal performance.

Features

  • 🎯 Fine-Grained Reactivity: Surgical DOM updates without virtual DOM overhead
  • 🔄 Dual-Mode JSX: Use native JSX or lit-html templates interchangeably
  • 🚀 Optimal Performance: Only updates what actually changed
  • 🧩 Control Flow: Built-in Show, For, Switch, Portal components
  • 📦 Signal & Store Support: Works with any reactive system
  • 🎨 Lit-HTML Integration: Full compatibility with lit-html directives
  • 🔧 Compiler Support: Includes transformation utilities for build-time optimization
  • 📘 Full TypeScript: Complete type safety with JSX intrinsic elements

Installation

npm install @fluixi/jsx @fluixi/dom
# or
pnpm add @fluixi/jsx @fluixi/dom
# or
yarn add @fluixi/jsx @fluixi/dom

Quick Start

Configure TypeScript

Add to your tsconfig.json:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "@fluixi/jsx",
    "types": ["@fluixi/jsx"]
  }
}

Basic Usage

import { render } from '@fluixi/jsx';
import { createSignal } from '@fluixi/reactive/signal';

function Counter() {
  const [count, setCount] = createSignal(0);

  return (
    <div>
      <p>Count: {count()}</p>
      <button onClick={() => setCount(count() + 1)}>
        Increment
      </button>
    </div>
  );
}

render(<Counter />, document.getElementById('app')!);

With Reactive Values

import { createSignal } from '@fluixi/reactive/signal';

function App() {
  const [name, setName] = createSignal('World');

  return (
    <div>
      {/* Reactive text - updates automatically */}
      <h1>Hello, {name()}!</h1>
      
      {/* Reactive attribute */}
      <input
        value={name()}
        onInput={(e) => setName(e.target.value)}
      />
    </div>
  );
}

JSX Syntax

Elements

// Native elements
<div className="container">Content</div>

// Self-closing
<img src="image.jpg" alt="Image" />

// Components
<MyComponent prop="value" />

Reactive Attributes

import { createSignal } from '@fluixi/reactive/signal';

const [color, setColor] = createSignal('red');
const [size, setSize] = createSignal(16);

<div
  style={{
    color: color(),           // Reactive
    fontSize: `${size()}px`   // Reactive
  }}
  className={`text-${color()}`}  // Reactive
  data-color={color()}            // Reactive
>
  Content
</div>

Event Handlers

// Click handler
<button onClick={() => console.log('clicked')}>
  Click me
</button>

// Input handler
<input onInput={(e) => console.log(e.target.value)} />

// Custom events
<div onCustomEvent={(e) => handleCustom(e)} />

Children

// Text children
<div>Hello World</div>

// Element children
<div>
  <span>Child 1</span>
  <span>Child 2</span>
</div>

// Reactive children
<div>{count()}</div>

// Array children
<div>
  {items().map(item => <div key={item.id}>{item.name}</div>)}
</div>

// Mixed children
<div>
  Static text
  {dynamic()}
  <span>Element</span>
</div>

Fragments

// Fragment shorthand
<>
  <div>First</div>
  <div>Second</div>
</>

// Named fragment
<Fragment>
  <div>First</div>
  <div>Second</div>
</Fragment>

Control Flow Components

Show

Conditional rendering with optional fallback.

import { Show } from '@fluixi/jsx';

function Profile() {
  const [user, setUser] = createSignal(null);

  return (
    <Show
      when={user()}
      fallback={<div>Loading...</div>}
    >
      {(u) => (
        <div>
          <h1>{u.name}</h1>
          <p>{u.email}</p>
        </div>
      )}
    </Show>
  );
}

For

Keyed list rendering with optimal updates.

import { For } from '@fluixi/jsx';

function TodoList() {
  const [todos, setTodos] = createSignal([
    { id: 1, text: 'Learn JSX', done: false },
    { id: 2, text: 'Build app', done: false },
  ]);

  return (
    <ul>
      <For each={todos()}>
        {(todo, index) => (
          <li>
            <input
              type="checkbox"
              checked={todo.done}
              onChange={(e) => updateTodo(index(), e.target.checked)}
            />
            {todo.text}
          </li>
        )}
      </For>
    </ul>
  );
}

Index

Index-based list rendering (use when items change but positions don't).

import { Index } from '@fluixi/jsx';

function NumberList() {
  const [numbers] = createSignal([1, 2, 3, 4, 5]);

  return (
    <ul>
      <Index each={numbers()}>
        {(num, index) => (
          <li>#{index}: {num()}</li>
        )}
      </Index>
    </ul>
  );
}

Switch/Match

Multi-way conditional rendering.

import { Switch, Match } from '@fluixi/jsx';

function StatusView() {
  const [status, setStatus] = createSignal('loading');

  return (
    <Switch fallback={<div>Unknown status</div>}>
      <Match when={status() === 'loading'}>
        <div>Loading...</div>
      </Match>
      <Match when={status() === 'success'}>
        <div>Success!</div>
      </Match>
      <Match when={status() === 'error'}>
        <div>Error occurred</div>
      </Match>
    </Switch>
  );
}

Portal

Render content in a different DOM location.

import { Portal } from '@fluixi/jsx';

function Modal({ isOpen, children }) {
  return (
    <Show when={isOpen()}>
      <Portal mount={document.body}>
        <div class="modal-backdrop">
          <div class="modal">
            {children}
          </div>
        </div>
      </Portal>
    </Show>
  );
}

Dynamic

Dynamically render components based on runtime conditions.

import { Dynamic } from '@fluixi/jsx';

function DynamicComponent() {
  const [component, setComponent] = createSignal('div');
  
  return (
    <Dynamic
      component={component()}
      className="dynamic"
    >
      Content
    </Dynamic>
  );
}

ErrorBoundary

Catch and handle errors in component trees.

import { ErrorBoundary } from '@fluixi/jsx';

function App() {
  return (
    <ErrorBoundary
      fallback={(err, reset) => (
        <div>
          <h1>Error: {err.message}</h1>
          <button onClick={reset}>Retry</button>
        </div>
      )}
    >
      <RiskyComponent />
    </ErrorBoundary>
  );
}

Lit-HTML Integration

Use lit-html templates alongside JSX.

With signal directive

import { html } from 'lit';
import { signal } from '@fluixi/jsx';

function Component() {
  const [count, setCount] = createSignal(0);

  return html`
    <div>
      <p>Count: ${signal(count)}</p>
      <button @click=${() => setCount(count() + 1)}>
        Increment
      </button>
    </div>
  `;
}

Helper utilities

import { template, templateSVG, $, $if } from '@fluixi/jsx';

function Component() {
  const [show, setShow] = createSignal(true);
  const [name, setName] = createSignal('World');

  // Auto-wrapped template
  return template`
    <div>
      ${$if(show, `Hello, ${$(name)}!`, 'Hidden')}
    </div>
  `;
}

Component Patterns

Function Components

interface Props {
  name: string;
  age: number;
}

function Greeting(props: Props) {
  return <div>Hello, {props.name} ({props.age})</div>;
}

With Children

interface CardProps {
  title: string;
  children: JSX.Element;
}

function Card(props: CardProps) {
  return (
    <div class="card">
      <h2>{props.title}</h2>
      <div class="card-body">
        {props.children}
      </div>
    </div>
  );
}

// Usage
<Card title="My Card">
  <p>Card content here</p>
</Card>

With Signals

function Counter(props: { initial?: number }) {
  const [count, setCount] = createSignal(props.initial ?? 0);

  return (
    <div>
      <p>Count: {count()}</p>
      <button onClick={() => setCount(c => c + 1)}>+</button>
      <button onClick={() => setCount(c => c - 1)}>-</button>
    </div>
  );
}

Memoized Components

import { memo } from '@fluixi/jsx';

const ExpensiveComponent = memo((props: { data: any }) => {
  // Expensive rendering logic
  return <div>{/* ... */}</div>;
});

Component Helpers

import { jsxComponent, defineComponent } from '@fluixi/jsx';

// Simple component wrapper
const MyComponent = jsxComponent((props: Props) => {
  return <div>{/* ... */}</div>;
});

// With name for debugging
const NamedComponent = defineComponent('MyComponent', (props: Props) => {
  return <div>{/* ... */}</div>;
});

Refs

Element Refs

import { createRef } from '@fluixi/jsx';

function Component() {
  const inputRef = createRef<HTMLInputElement>();

  const focusInput = () => {
    inputRef.current?.focus();
  };

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={focusInput}>Focus</button>
    </div>
  );
}

Callback Refs

function Component() {
  let divElement: HTMLDivElement | null = null;

  const handleRef = (el: HTMLDivElement | null) => {
    divElement = el;
    if (el) {
      console.log('Element mounted:', el);
    }
  };

  return <div ref={handleRef}>Content</div>;
}

Forward Ref

import { forwardRef } from '@fluixi/jsx';

const FancyInput = forwardRef<HTMLInputElement, { label: string }>(
  (props, ref) => {
    return (
      <div>
        <label>{props.label}</label>
        <input ref={ref} />
      </div>
    );
  }
);

// Usage
const inputRef = createRef<HTMLInputElement>();
<FancyInput label="Name" ref={inputRef} />

Styling

Inline Styles

// Object style
<div style={{ color: 'red', fontSize: '16px' }}>
  Styled text
</div>

// String style
<div style="color: red; font-size: 16px;">
  Styled text
</div>

// Reactive styles
<div style={{ color: color() }}>
  Dynamic color
</div>

CSS Classes

// String
<div className="btn btn-primary">Button</div>

// Array
<div className={['btn', isActive() && 'active'].filter(Boolean)}>
  Button
</div>

// Object (with classMap from lit)
import { classMap } from 'lit/directives/class-map.js';

<div className={classMap({ btn: true, active: isActive() })}>
  Button
</div>

// Reactive
<div className={`btn btn-${type()}`}>Button</div>

Advanced Usage

Batch Updates

import { jsxBatch } from '@fluixi/jsx';

function Component() {
  const [a, setA] = createSignal(0);
  const [b, setB] = createSignal(0);
  const [c, setC] = createSignal(0);

  const updateAll = () => {
    jsxBatch(() => {
      setA(1);
      setB(2);
      setC(3);
    });
    // Only one render cycle
  };

  return <button onClick={updateAll}>Update All</button>;
}

Server-Side Rendering

import { renderToString } from '@fluixi/jsx';

async function handler() {
  const html = await renderToString(<App />);
  return new Response(html, {
    headers: { 'Content-Type': 'text/html' },
  });
}

Hydration

import { hydrate } from '@fluixi/jsx';

// Hydrate server-rendered content
hydrate(<App />, document.getElementById('app')!);

Compiler Options

The package includes a compiler module for build-time optimizations.

Transform JSX

import { transform } from '@fluixi/jsx/compiler';

const result = transform(code, {
  useLitHTML: true,
  optimize: true,
  delegateEvents: true,
  delegatedEvents: ['click', 'input', 'change'],
});

console.log(result.code);
console.log(result.metadata);

Babel Plugin

// babel.config.js
module.exports = {
  plugins: [
    ['@fluixi/jsx/compiler/babel', {
      useLitHTML: true,
      optimize: true,
    }]
  ]
};

TypeScript Transformer

import { createTypeScriptTransformer } from '@fluixi/jsx/compiler';

const transformer = createTypeScriptTransformer({
  optimize: true,
});

Performance Tips

  1. Use For for lists: Keyed reconciliation is faster than mapping
  2. Memoize expensive components: Use memo() wrapper
  3. Batch updates: Use jsxBatch() for multiple state changes
  4. Avoid inline object creation: Extract to variables
  5. Use Index for stable lists: When order doesn't change
// ❌ Bad - creates new object every render
<div style={{ color: 'red' }}>Text</div>

// ✅ Good - object is stable
const style = { color: 'red' };
<div style={style}>Text</div>

// ❌ Bad - new function every render
<button onClick={() => handleClick(id)}>Click</button>

// ✅ Good - stable function
const handleClick = () => handleClick(id);
<button onClick={handleClick}>Click</button>

TypeScript

Component Types

import type { JSXElement, JSXComponent } from '@fluixi/jsx';

// Function component type
const Component: JSXComponent<{ name: string }> = (props) => {
  return <div>{props.name}</div>;
};

// Element type
function render(): JSXElement {
  return <div>Content</div>;
}

Props Interface

import type { JSXProps } from '@fluixi/jsx';

interface MyProps extends JSXProps {
  title: string;
  count: number;
  onUpdate?: (value: number) => void;
}

function MyComponent(props: MyProps) {
  return <div>{props.title}: {props.count}</div>;
}

Intrinsic Elements

// All HTML elements are typed
<div>Text</div>
<button onClick={() => {}}>Button</button>
<input type="text" value="text" />

// With proper event types
<button onClick={(e: MouseEvent) => console.log(e)}>
  Click
</button>

<input onInput={(e: InputEvent) => {
  const target = e.target as HTMLInputElement;
  console.log(target.value);
}} />

Browser Support

  • Modern browsers (Chrome, Firefox, Safari, Edge)
  • ES2020+ required
  • No IE11 support

Debugging

Development Mode

import { createReactiveJSX } from '@fluixi/jsx';

const jsx = createReactiveJSX({
  signalSystem: mySignalSystem,
  development: true, // Enables warnings and checks
});

Component Names

Use defineComponent for better debugging:

import { defineComponent } from '@fluixi/jsx';

const MyComponent = defineComponent('MyComponent', (props) => {
  return <div>{props.children}</div>;
});

Migration Guide

From React

// React
import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return <div onClick={() => setCount(count + 1)}>{count}</div>;
}

// This package
import { createSignal } from '@fluixi/reactive/signal';

function Counter() {
  const [count, setCount] = createSignal(0);
  return <div onClick={() => setCount(count() + 1)}>{count()}</div>;
}
// Note: Signals are functions!

From Solid

// Very similar! Main difference is import paths
import { createSignal, Show, For } from 'solid-js';
// becomes
import { createSignal } from '@fluixi/reactive/signal';
import { Show, For } from '@fluixi/jsx';

Examples

Check the examples directory for complete applications:

  • Counter app
  • Todo list
  • Data fetching
  • Forms
  • Routing

Contributing

Contributions welcome! Please see the main repository for guidelines.

License

MIT

Related Packages

  • @fluixi/dom - Core reactive DOM runtime
  • @fluixi/reactive - Signal and store implementations
  • lit - Template literals for HTML

Resources