Skip to content
Switch branches/tags
Go to file

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


the smallest component renderer

Introducing: Bad-DOM - the smallest* component renderer

*seriously, it's 592 bytes minified + gzipped

What does it do?

Bad-DOM is a lazy diffing algorithm and HTML component renderer. It's lazy because it doesn't try too hard to keep the browser from doing unnecessary work, but still does a pretty good job.

Bad-DOM exposes a single function, vDiff, which takes 2 parameters. The first being an existing element on the page, and the second being a template string representing the markup you would like to replace the first item with.

Calling this function will result in parameter 1 being replaced by parameter 2, with the goal of the least amount of changes taking place in the DOM in order to achieve that replacement. Here's what that would look like using some "hello world" text in a p tag:

vDiff(document.querySelector('.hello-world-demo'), `<p class="hello-world-demo">GoodBye!</p>`)

In this example, we're taking an element from the page (a paragraph tag with text in it that says "hello world!") and changing the text inside it. Bad-DOM knows not to change anything other than the text, because it can tell that nothing else has changed.

What else does it do?

Since Bad-DOM takes a template string as its second parameter, it becomes a fully capable component renderer as well.

For example, given an html page with an empty element: <div id="My-App"></div>

We can render markup into our My-App container:

const name = 'Tim';
vDiff(document.querySelector('#My-App'), `<div id="My-App">Hello, ${name}</div>`);

An example of this behavior can be found here, wherein a working image slider is being rendered into the dom and transitioned based on a counter state.

Here's the code necessary to render the slider:

document.querySelector('button').addEventListener('click', () => {
  x = (x === 3 ? 0 : x + 1);
	    <img style="display:${x === 1 ? 'block' : 'none'}" src="" alt="phones p much">
	    <img style="display:${x === 2 ? 'block' : 'none'}" src="" alt="peeps">
	    <img style="display:${x === 0 ? 'block' : 'none'}" src="" alt="woofers">
	    <img style="display:${x === 3 ? 'block' : 'none'}" src="" alt="outside">

Why should I use this thing?

Since Bad-DOM is a fully capable component renderer, you can use it to build fully capable UI's. An example is provided here:

For the above demo application to work, all we need to do is include the Bad-DOM library, provide a render target, and feed the vDiff function a template string. After the initial rendering takes place, the inline event handlers reference functions that update the global app state and rebuild the template string. No more DOM manipulation, render-hacks, or confusing framework methods to memorize.

Overall, you can use Bad-DOM to build powerful components as long as you provide your own state management and event systems. In the counter demo referenced above, basic inline html events are being used, while each callback function is only responsible for updating the application state and calling the render function. Essentially, Bad-DOM's advantage is that it doesn't keep any internal memory, but is still able to intelligently update the DOM based on whatever source it is given. Since Bad-DOM doesn't provide any reoccuring update functionality (you need to tell it to re-render explicitly) your application will be less likely to fall into common performance pitfalls seen with other component renderers.


  • Bad-DOM is fast.
  • Bad-DOM is small.
  • Bad-DOM is incredibly easy to use.


the smallest component renderer




No releases published


No packages published