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

vanillaforge

v1.9.2

Published

VanillaForge - A modern, lightweight vanilla JavaScript framework for forging Single Page Applications

Readme

VanillaForge

A small, zero-dependency JavaScript framework for building Single Page Applications with plain web standards.

License: MIT ES Modules Tests

VanillaForge gives you components, client-side routing, and an event bus in a few small ES modules — no dependencies and no required build step. It runs straight from src/ in the browser; the build is only for producing an optimized bundle.

Why VanillaForge?

  • Zero runtime dependencies — ships as plain ES modules.
  • Small — the core is ~14.5 KB min+gzip (~48 KB minified).
  • Batteries-included — icons, CSS/theming, alerts, self-hosted fonts, and a shared reactive store, all built in. No Font Awesome, Bootstrap, SweetAlert, or Google Fonts required — but you can still bring them in if you want.
  • Component composition — embed child components directly inside parent templates. Each child has isolated state, props, lifecycle, and event handling.
  • Plugin system — every subsystem (icons, theme, alerts, fonts, store) is a plugin you can install, replace, or skip.
  • Efficient updates — re-renders are applied with a tiny DOM-morphing diff, so only changed nodes are touched and focused inputs keep their cursor (see How rendering works).
  • Client-side routing — history API, route params (/users/:id), and a configurable fallback route.
  • Declarative events — wire DOM events to methods with data-* attributes; the framework handles delegation and cleanup.

Quick Start

Scaffold a new project

npx create-vanillaforge my-app
cd my-app
npm install
npm run dev

The CLI prompts for a template. Pass --template=<name> to skip the prompt:

npx create-vanillaforge my-app --template=minimal   # no plugins
npx create-vanillaforge my-app --template=full       # all plugins
npx create-vanillaforge my-app --template=todo-app
npx create-vanillaforge my-app --template=router-app

See create-vanillaforge/README.md for the full CLI reference.

Install in an existing project

npm install vanillaforge

Work on the framework itself

git clone https://github.com/Steve-GitCodex/vanillaforge.git
cd vanillaforge
npm install
npm run dev          # build to dist/ and serve
npm run example      # Todo app (no build needed)
npm run example:router   # Routing + params demo

Your first component:

import { createApp, BaseComponent, iconsPlugin } from './src/framework.js';

class HelloWorld extends BaseComponent {
    constructor(eventBus, props = {}) {
        super(eventBus, props);
        this.name = 'hello-world';
        this.state = { count: 0 };
    }

    getTemplate() {
        return `
            <div class="hello">
                <h1>Hello, VanillaForge!</h1>
                <p>Clicked ${this.state.count} times.</p>
                <button data-action="inc">
                    ${this.icon('plus', { size: 16 })} Click me
                </button>
            </div>
        `;
    }

    getMethods() {
        return { inc: () => this.setState({ count: this.state.count + 1 }) };
    }
}

const app = createApp({ debug: true });
app.use(iconsPlugin);                                   // built-in SVG icons
await app.initialize({ routes: { '/': HelloWorld } });
await app.start();

The page needs a mount element (default id main-content, configurable via createApp({ mountId })):

<div id="main-content"></div>
<script type="module" src="./app.js"></script>

How rendering works

Calling setState() re-runs your getTemplate() and morphs the result onto the live DOM instead of replacing innerHTML. The morph:

  • patches only attributes/text/nodes that actually changed;
  • preserves the focus and caret/selection of a focused input, so typing is never interrupted by a re-render;
  • reconciles lists by data-key, so reordering or removing an item reuses the existing DOM nodes instead of rebuilding the list.
getTemplate() {
    return `<ul>${this.state.items
        .map((it) => `<li data-key="${it.id}">${it.label}</li>`)
        .join('')}</ul>`;
}

Note: a full re-render still re-runs the whole template (then diffs it). Moving to fine-grained, signal-based updates is on the roadmap.

Declarative events

Bind DOM events to getMethods() entries with attributes. Each attribute maps to exactly one event so a handler fires once:

| Attribute | Fires on | Typical use | | -------------- | --------- | --------------------------- | | data-action | click | buttons, links | | data-change | change | checkboxes, radios, selects | | data-input | input | text inputs, textareas | | data-keydown | keydown | keyboard shortcuts | | data-submit | submit | forms |

Handlers receive (event, matchedElement). Listeners are delegated to the component's root element once and cleaned up automatically on destroy.

Examples

  • Todo App — local state, filtering, keyed list, and focus-preserving input. Run with npm run example.
  • Routing demo — a list view and a /users/:id detail view driven by route params. Run with npm run example:router.

Testing

Tests run on Vitest with happy-dom (dev dependencies only — the framework itself stays dependency-free):

npm test

Coverage includes the DOM morph (focus/selection preservation, keyed lists), the component lifecycle and event delegation, the router, the event bus, and both examples.

Build

npm run build               # bundle src/app.js + CSS into dist/
NODE_ENV=production npm run build   # minified bundle

The build uses esbuild to bundle and tree-shake, and copies/minifies discovered CSS. See docs/build-system.md.

Documentation

For maintainers returning after time away: see DEVELOPMENT.md.

Security

Templates return plain HTML strings — escape all user-supplied values before interpolating them. VanillaForge ships a dedicated helper:

import { escapeHtml, html } from 'vanillaforge';  // or from './src/framework.js'

// Escape individual values
getTemplate() {
  return `<h1>${escapeHtml(this.state.title)}</h1>`;
}

// Or use the html tagged template — every interpolation is auto-escaped
getTemplate() {
  return html`<h1>${this.state.title}</h1>`;
}

this.icon() and this.child() already return safe RawHtml — no extra escaping needed. See Components — Escaping and XSS.

Content Security Policy: the theme, alerts, and fonts plugins inject <style> elements at runtime, so your CSP requires style-src 'unsafe-inline' (or a nonce/hash approach). Stricter CSP support is on the roadmap.

Browser Support

Modern browsers with ES2020+ support: Chrome 80+, Firefox 72+, Safari 14+, Edge 80+.

Roadmap

All five built-in plugins (icons, theme, alerts, fonts, store), component composition, signals, route loaders, TypeScript types, the scaffold CLI, and npm publication of both vanillaforge and create-vanillaforge are complete.

Full release history in CHANGELOG.md.

Contributing

Issues and pull requests are welcome. Please run npm test and npm run lint before opening a PR.

License

MIT — see LICENSE.


Author: Stephen Musyoka · GitHub · Issues