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

@tltdsh/mx

v1.0.7

Published

Sub-1KB reactive DOM reconciliation engine for building massive platforms and user interfaces at scale. 862 bytes brotli, zero dependencies, no build step. Small enough for AI context windows.

Downloads

798

Maintainers

tltdshtltdsh

Keywords

uiui-libraryui-frameworkui-enginedomdom-reconciliationdom-diffingdom-patchingdom-manipulationdom-firstreactivereactivityrenderrenderingreconciliationdiffpatchcomponentscomponent-systemcustom-elementsweb-componentsdeclarativeviewview-layertemplatingstate-managementdata-bindingfrontendfront-endframeworkmicro-frameworkenginetinylightweightultra-lightweightminimalminimalistsmallmicro1kbsub-1kbfastperformanthigh-performanceefficientzero-overheadzero-dependencyzero-dependenciesno-dependenciesdependency-freeno-buildno-bundlerno-compileno-toolingno-jsxvirtual-domvdomno-virtual-dombuildlesscdncdn-readyscript-tagesmes-modulesvanillavanilla-jsvanilla-javascriptplain-javascriptplain-jspure-javascriptbrowserbrowser-nativeclient-sidewebwebappspasingle-page-apphtmlsvgjavascriptjstypescriptproxykeyedkeyed-listllm-friendlyai-friendlycontext-windowcopilot-friendlyvibe-codingprompt-friendlyai-firstsingle-filereact-alternativejquery-alternativepreact-alternativevue-alternativesvelte-alternativeangular-alternativehtmx-alternativeunopinionatedsimplebeginner-friendlyenterpriseenterprise-gradeenterprise-uiproductionproduction-readyproduction-gradelarge-scaleat-scalemassivesaasb2bb2cfintechmedtechhealthtechedtechdashboardadmin-panelback-officedata-drivendata-visualizationreal-timerealtimelive-updateprotocolstable-apiapi-stablesemverlong-termfuture-proofbackwards-compatiblescalablemission-criticalultra-fastultrafastsuperfastblazing-fastinstantsnappylow-latencyzero-latencysub-millisecond60fpssmoothjank-freememory-efficientlow-memorysmall-footprintzero-bloatno-bloatleanslimcompactnanofeatherweightatomicmodularcomposableextensibleembeddableportableuniversalisomorphicssr-compatiblessgstatic-sitejamstackheadlesscmswidgetmicro-frontendmicro-appislandislands-architectureprogressive-enhancementgraceful-degradationaccessiblea11yresponsivemobile-firstpwaofflineweb-platformplatformapp-frameworkapplication-frameworkcrudformformstablelistgridcharttreetree-viewtabsmodaldropdowntooltipnotificationtoastanimationtransitionroutingrouternavigationlazy-loadingvirtual-scrollinfinite-scrollpaginationsearchfiltersortdrag-and-dropevent-drivenevent-handlinglifecyclehooks-freeclass-freefunctionalimperativedirect-domreal-domdom-apielementnodehtml5css3modern-webweb-standardstandards-compliantcross-browserchromefirefoxsafariedgewebkitblinkv8javascriptcorespidermonkeydenobunnodenpmyarnpnpmopen-source0bsdmitfreeno-license-restrictioncommercial-friendlystartupindieindie-hackersolo-developerside-projectmvpprototyperapid-developmentrapid-prototypinghackathoncode-golfdemoscenejs13ksize-optimizedbrotli-optimizedgzip-optimizedcompression-friendlybandwidth-efficientedge-computeedge-functionserverlesscloudflare-workerslambdavercelnetlifyfirebasedeno-deployfly-io

Readme

mx.js

Sub-1KB reactive DOM reconciliation engine for building massive platforms and user interfaces at scale. 862 bytes brotli. 4 globals, zero dependencies, no virtual DOM, no build step. Small enough to fit in an AI context window.

Documentation

Install

CDN (recommended)

<!-- jsDelivr (multi-CDN, recommended) -->
<script src="https://cdn.jsdelivr.net/npm/@tltdsh/mx"></script>

<!-- unpkg -->
<script src="https://unpkg.com/@tltdsh/mx"></script>

Pinned version

<script src="https://cdn.jsdelivr.net/npm/@tltdsh/[email protected]/mx.min.js"></script>

npm / yarn / bun

npm i @tltdsh/mx

ESM (bundler)

import { mx, dom, define, components } from '@tltdsh/mx'

ESM (dynamic import from CDN)

const { mx, dom, define, components } = await import('https://cdn.jsdelivr.net/npm/@tltdsh/mx/mx.mjs')

Works in any modern browser or Deno - no install, no bundler, one line.

4 Globals

| Global | Returns | Use for | |--------|---------|---------| | mx.tag(attrs?, ...children) | Description array | Inside render() - efficient reconciliation | | dom.tag(attrs?, ...children) | HTMLElement | Persistent references, calling .$() later | | define(name, { $() {} }) | void | Register a component | | components | object | Component registry |

CamelCase auto-converts to kebab-case: mx.priceChart()<price-chart>.

Quick start

define('counter', {
    $({ count = 0 }) {
        return [
            mx.button({ onclick: _ => this.$({ count: count + 1 }) }, '+'),
            mx.span(count),
            mx.button({ onclick: _ => this.$({ count: count - 1 }) }, '-')
        ]
    }
})

document.body.render(mx.counter({ count: 10 }))

Examples

SVG sparkline

define('sparkline', {
    $({ history = [], width = 80, height = 24 }) {
        if (!history.length) return []
        let min = Math.min(...history), max = Math.max(...history)
        let range = max - min || 1
        let points = history.map((v, i) =>
            (i / (history.length - 1) * width).toFixed(1) + ',' +
            (height - ((v - min) / range * (height - 2) + 1)).toFixed(1)
        ).join(' ')
        return mx.svg({ viewBox: '0 0 ' + width + ' ' + height, width, height, fill: 'none' },
            mx.polyline({ points, stroke: '#0071e3', 'stroke-width': '1.5', 'stroke-linecap': 'round' })
        )
    }
})

Sortable table

define('data-table', {
    $({ rows = [], sortKey = 'name', sortDir = 1 }) {
        let sorted = [...rows].sort((a, b) => {
            let va = a[sortKey], vb = b[sortKey]
            return sortDir * (typeof va === 'string' ? va.localeCompare(vb) : va - vb)
        })
        let header = (label, key) =>
            mx.th({ onclick: _ => this.$({ sortKey: key, sortDir: sortKey === key ? -sortDir : 1 }) },
                label, sortKey === key ? (sortDir > 0 ? ' ▲' : ' ▼') : null
            )
        return mx.table(
            mx.thead(mx.tr(header('Name', 'name'), header('Value', 'value'))),
            mx.tbody(...sorted.map(r => mx.tr(mx.td(r.name), mx.td(r.value))))
        )
    }
})

Keyed list with persistent DOM

define('drink-builder', {
    $({ drinks = [], onadd, onremove }) {
        this._rowMap ||= new Map
        for (let [id] of this._rowMap)
            if (!drinks.find(d => d.id === id)) this._rowMap.delete(id)
        for (let d of drinks) {
            let el = this._rowMap.get(d.id)
            if (!el) { el = dom.drinkRow(); this._rowMap.set(d.id, el) }
            el.$({ drink: d, onremove })
        }
        return [
            !!drinks.length && mx.div({ class: 'list' },
                ...drinks.map(d => this._rowMap.get(d.id))
            ),
            mx.button({ onclick: _ => onadd?.() }, '+ Add drink')
        ]
    }
})

Toast notifications

let toastContainer = null

function toast(message, type = 'info') {
    if (!toastContainer) {
        toastContainer = dom.div({ class: 'toast-container' })
        document.body.append(toastContainer)
    }
    let el = dom.div({ class: 'toast toast-' + type },
        mx.span(message),
        mx.button({ onclick() { el.remove() } }, '×')
    )
    toastContainer.append(el)
    setTimeout(_ => el.remove(), 4000)
}

toast.success = msg => toast(msg, 'success')
toast.error = msg => toast(msg, 'error')

How it works

render(...children) reconciles children left-to-right against existing DOM:

  • mx.*() descriptions → create/reuse elements by tag, apply attrs, recurse
  • Real DOM nodes → identity-match by reference (keyed lists)
  • Strings / numbers → text nodes (auto-cast, no String() needed)
  • null / false → skipped (conditional rendering)

Excess old nodes are removed. That's it.

Attributes

mx.div({ class: 'active' })          // setAttribute
mx.input({ '.value': text })         // el.value = text (property)
mx.button({ disabled: true })        // setAttribute(name, '')
mx.button({ disabled: null })        // removeAttribute
mx.button({ onclick: handler })      // el.onclick = handler (auto-cleaned)

value, checked, selected set both attribute and property automatically.

Keyed lists

Create persistent elements with dom(), store in a Map, render by reference:

let rowMap = new Map(
    data.map(d => [d.id, dom.tableRow({ data: d })])
)

// Nodes move by identity - internal state preserved on reorder
container.render(...data.map(d => rowMap.get(d.id)))

Tips

  • mx.* = descriptions (arrays) for inside render()
  • dom.* = real HTMLElements for persistent references
  • $() always returns array of children
  • ??= protects $state from parent prop overwrites
  • Never addEventListener inside $() - use direct property assignment
  • Numbers auto-cast - no String() needed
  • Use _ => for unused arrow params
  • clearInterval(this._interval) at top of $() for timers
  • this._cache ||= new Map for persistent Maps

TypeScript

Full type definitions included. Provides autocomplete for all HTML/SVG elements and attributes.

import { mx, dom, define, type MxChild, type MxAttrs } from '@tltdsh/mx'

License

0BSD - do whatever you want.