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

bang.html

v10.1.2

Published

BANG! Web Component custom elements with async templating, smooth syntax and custom void tags!

Readme

GOOD (BANG!)

npm npm

GOOD is a zero-dependency Web Components UI framework that favors real HTML, real CSS, and real DOM updates. It pairs custom elements with minimal granular DOM patching, async templating, and file-based components so you can build UI with no build step and no JSX.

[!NOTE] GOOD is the project name. The published package is bang.html on npm, and the runtime global API is use, setState, and friends.

[!IMPORTANT] Bang tags are valid HTML comment nodes that GOOD upgrades into Custom Elements. Example: <!my-card /> becomes <my-card></my-card>.

[!TIP] Use lazy and super on components to load heavy or below-the-fold UI without blocking page load. Example: <sg-table super lazy state=cells2></sg-table> from the 7GUIs demo.

Why GOOD

  • File-based components: components/name/markup.html, style.css, and script.js are optional and auto-wired.
  • Granular DOM updates: no VDOM, no Shadow DOM diffing. Updates hit only the text, attributes, and list segments that changed.
  • Custom element ergonomics: declarative use('my-thing') with scoped Shadow DOM styles and optional script hooks.
  • Async templating: Promises and async functions can render inline with ${...} and resolve automatically.
  • Incremental load: lazy and super attributes prioritize critical UI first.

Demos

  • 7GUIs: https://crisdosyago.github.io/good.html/7guis/
  • Cells spreadsheet (WIP): https://crisdosyago.github.io/good.html/cellophane/
  • Simple counter: https://crisdosyago.github.io/good.html/ctr/

Quick start

CDN

<!doctype html>
<script src=https://unpkg.com/bang.html></script>
<link rel=stylesheet href=https://unpkg.com/bang.html/src/style.css>
<script>
  use('sg-counter');
  setState('ctr', {count: 0});
</script>
<!sg-counter state=ctr />

npm

npm i --save bang.html

Component anatomy

Each component lives in components/<name>/ and can define any of the files below.

components/
  sg-counter/
    markup.html
    style.css
    script.js

Example pulled from the 7GUIs components:

docs/components/sg-counter/markup.html

<sg-frame state=${_self}>
  <button id=counter onclick=Increment>Count</button>
  <label for=counter>${count}</label>
</sg-frame>

docs/components/sg-counter/script.js

class Counter extends Base {
  Increment() {
    const {state} = this;
    state.count++;
    this.state = state;
  }
}

docs/components/sg-counter/style.css

label {
  min-width: 4.5ch;
  display: inline-block;
  text-align: right;
}

State and templating

State is stored by key and referenced by components using state=.

setState('MyState', {
  name: 'Uncle Bob',
  greetCounts: {value: 1}
});
<!warm-greeter state=MyState />

Within markup.html, state properties are in scope for ${...} slots:

<h1>Hello ${name}</h1>
<p>We are very pleased to meet you <greet-count state=${greetCounts}>happy</greet-count> times</p>

Nested objects passed through ${...} become component state automatically, just like a named state key.

Granular updates (no VDOM)

GOOD uses the vanillaview update engine for direct DOM patching. Lists, text nodes, and attribute values are updated in place. This is real DOM work, not a VDOM reconcile, and the update engine does not rely on Shadow DOM diffing. Components still render into Shadow DOM for style scoping, but updates are granular and direct.

Lazy and super lazy loading

Add lazy to avoid blocking parent render. Add super for even later scheduling.

<!sg-cells lazy state=cells2 />
<sg-table super lazy state=cells2></sg-table>

Docs and examples

  • Docs landing page: docs/index.html
  • 7GUIs app: docs/7guis/index.html
  • 7GUIs components source: docs/components/

If you want a bigger real app, see ../BrowserBox-public/src/public/voodoo/src/.

Comparison (no benchmarks)

| Framework | Primary abstraction | Component format | Build step | Shadow DOM | Rendering model | | --- | --- | --- | --- | --- | --- | | GOOD (BANG!) | Custom Elements + bang tags | markup.html + style.css + script.js | Optional | Yes (scoped styles) | Direct DOM updates (no VDOM) | | React | Components | JSX | Yes | No | VDOM reconcile | | Vue | Components | SFC or JSX | Usually | No | VDOM + compiler | | Svelte | Components | SFC | Yes | No | Compile-time DOM updates | | Lit | Custom Elements | JS template literals | Optional | Yes | Template render + update | | Solid | Components | JSX | Yes | No | Fine-grained reactive DOM |

FAQ (short)

Why bang tags instead of <my-tag />? HTML parses self-closing non-void tags as open tags, so you do not get a true empty element. Bang tags sidestep this by using a comment node and upgrading it to a Custom Element.

How do I attach events? Define a method on your component class and reference it by name in onclick= (or any standard DOM event).

What is required in a component? Nothing. Any of markup.html, style.css, and script.js can be omitted.

Contributing

Issues and PRs are welcome. Keep patches focused and feel free to link to a demo or reproduction.