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-jotlang

v0.6.4

Published

JOTLANG on top of SolidJS — Vite plugin that compiles .jot files to reactive Solid components.

Readme

solid-jotlang

A SolidJS compiler for JOTL — write reactive, component-based interfaces in JOTL's whitespace-sigil syntax and ship them as fine-grained reactive SolidJS components.

>> component Counter:
  >> props: {
    initial: number
  }

  >> script [type=typescript]: {
    import { signal } from "solid-js"

    let count = signal(props.initial)

    increment () {
      count = count() + 1
    }
  }
  <<

  >> document:
    > heading.1: Counter <
    > text: Clicks: &count <
    > button [on_press=@increment]: Add <
  << document
<< component

Why

jotl (the standalone compiler) emits static HTML and a tiny runtime — ideal for documents, marketing sites, and progressively enhanced pages.

solid-jotlang takes the same .jot source and emits SolidJS components instead, so you get:

  • Fine-grained reactivity (no virtual DOM diff)
  • Real signals, memos, effects, and resources
  • Idiomatic Solid control flow (<Show>, <Switch>, <For>)
  • Components, props, slots, and a full SPA build pipeline via Vite

The compiler is opinionated about reactivity but small in surface area: the only new directive is >> component:, and the only new convention is that signals are explicit (let x = signal(0)).

Install

npm install solid-jotlang solid-js vite vite-plugin-solid -D

New to solid-jotlang? The Getting Started guide walks you through a brand-new project, from npm create vite to a working reactive counter with scoped styles and SEO meta tags.

solid-js and vite are peer dependencies. vite-plugin-solid handles the JSX-to-DOM transform and is required.

Usage with Vite

// vite.config.ts
import { defineConfig } from 'vite'
import solid from 'vite-plugin-solid'
import solidJotlang from 'solid-jotlang/vite'

export default defineConfig({
  plugins: [
    solidJotlang(),
    solid({ extensions: ['.jot'] }),
  ],
})

Then import a .jot module like any other Solid component:

// src/main.tsx
import { render } from 'solid-js/web'
import { Counter } from './Counter.jot'

render(() => <Counter initial={0} />, document.getElementById('root')!)

Files: component-mode and document-mode

A single .jot file may declare any number of components. The new >> component Name: directive is a meta-wrapper — it can contain its own >> props:, >> script:, >> style:, and >> document: blocks.

>> component HelloBadge:
  >> props: {
    label: string
  }

  >> document:
    > text [class=badge]: {props.label} <
  << document
<< component

>> component HelloPanel:
  >> document:
    !> HelloBadge [label="Hi there"]
  << document
<< component

If the file has no >> component: blocks but does have a top-level >> document:, the compiler emits a single exported component called Default. So the simplest case requires no extra ceremony:

>> document:
  > heading.1: Hello <
<< document
import Default from './hello.jot'

Reactivity contract

JOTL-Solid is explicit — you mark reactivity yourself, the compiler rewrites it.

| You write | Compiler emits | |--------------------------------------|---------------------------------------------| | let count = signal(0) | const [count, setCount] = createSignal(0) | | let total = memo(() => a() + b()) | const total = createMemo(() => a() + b()) | | let user = resource(fetchUser) | const [user] = createResource(fetchUser) | | effect(() => console.log(count())) | createEffect(() => console.log(count())) | | count = count() + 1 | setCount(count() + 1) |

Reads call the signal — count() in expressions, exactly the Solid convention. Writes look like ordinary assignments because the compiler rewrites them to setter calls.

Inside JOTL markup, &count automatically calls the signal:

> text: Clicks: &count <

…compiles to roughly:

<p>Clicks: {count()}</p>

ES import statements at the top of a >> script: body are hoisted to the module prelude.

Control flow

JOTL's control sigils lower to Solid's flow components:

| JOTL | Solid | |-------------------------------------|---------------------------------------------------------| | ~ if (&isOpen)~< | <Show when={isOpen()}>…</Show> | | ~ if … ~ elif … ~ else … ~< | <Switch><Match …>…</Match></Switch> | | ~ for (&items as $item)~< | <For each={items()}>{(item) => …}</For> |

This means a single signal change updates only the affected node — no component-level re-render.

Classless base stylesheet (optional)

solid-jotlang ships the same ~9 KB classless preset the JOTLANG HTML compiler inlines into every page. Three entry points, pick whichever fits your setup:

// 1. CSS import — idiomatic with Vite / bundlers.
import 'solid-jotlang/styles.css'

// 2. Runtime inject — for embedded widgets, tests, Shadow DOM hosts, etc.
import { injectBaseStyles } from 'solid-jotlang/styles'
injectBaseStyles()

// 3. Raw string — for SSR, email templates, or manual `<style>` nodes.
import { BASE_CSS } from 'solid-jotlang/styles'

The stylesheet targets raw HTML elements directly (no utility classes) and exposes a --jotl-* token surface so you can re-skin the app by overriding custom properties. Author styles always win — the preset is injected at the top of <head>, so anything you load or write after it cascades over it without !important. A JOTLANG page and a solid-jotlang app look identical by default; the compiled HTML side is documented in packages/compiler/styles/README.md.

What gets emitted

compile(source, { id }) returns a { code, map? } pair where code is plain ECMAScript (with JSX) — no TypeScript syntax, so it travels cleanly through Vite's SSR transform and any other tool that doesn't strip types.

Per-file output:

  • Top-level >> script: is emitted at module scope, after any hoisted imports.
  • Top-level >> style: is wrapped in a one-shot ensureGlobalStyle(...) helper that injects the CSS into <head> once per page.
  • >> component Name: becomes export function Name(props) { … }.
  • >> props: is emitted as a JSDoc @typedef and @param on the component, so editors get type hints without any TypeScript syntax in the output.

Programmatic API

import { compile, compileAst } from 'solid-jotlang'

const { code } = compile(source, { id: 'Counter.jot' })

compileAst accepts an already-parsed JOTL AST (from jotl) when you want to share parsing cost across passes.

Status

Public preview. The grammar is stable (it's the same JOTL the standalone compiler accepts) but the codegen is iterating — if you build something with this, please open an issue with the JOTL source and the output you expected.