diffHTML

v1.0.0-beta.17

An easy-to-use Virtual DOM built for the web!


Parser

A core feature of diffHTML is the HTML/XML/SVG parser. This is used whenever you pass a string of markup or use the html tagged template to innerHTML / outerHTML . While this code is optimized specifically for the VDOM and is very fast, you may want to optimize out the parser using the Babel plugin .

The parser can read full HTML documents including doctype, html/head/body/title etc tags, unwrapped fragments, and more!

Using with innerHTML:

import { innerHTML } from 'diffhtml';

// Using innerHTML will parse the HTML markup from a string literal.
innerHTML(document.body, '<div>Hello world</div>');

This produces a single top level element <div/> with a nested #text node.

If you were to structure your code like this:

import { innerHTML } from 'diffhtml';

// Using innerHTML will parse the HTML markup from a string literal.
innerHTML(document.body, '<div>Hello world</div>');

This would become:

import { createTree } from 'diffhtml';

innerHTML(document.body, createTree('div', null, [
  createTree('#text', 'Hello world')
]));

You'll notice the top-level element returned is 'div'. From there you may think:

import { innerHTML } from 'diffhtml';

// Using innerHTML will parse the HTML markup from a string literal.
innerHTML(document.body, `
  <div>Hello world</div>
`);

Would produce similar behavior, but it does not. The returned value mirrors what is embedded precisely, becoming:

import { createTree } from 'diffhtml';

innerHTML(document.body, createTree('#document-fragment', [
  createTree('#text', '\n'),
  createTree('div', null, [createTree('#text', 'Hello world')]),
  createTree('#text', '\n'),
]));

This can be useful knowledge for optimizing, but for more applications it should be fine to keep them in for developer convenience.

Using with outerHTML:

import { outerHTML } from 'diffhtml';

// Using outerHTML will parse the HTML markup and apply around the element.
outerHTML(document.body, `
  <body>Hello world</body>
`);

Using with html:

import { html } from 'diffhtml';

// The tagged template will parse HTML in the same way, and also handle
// dynamic values directly.
console.log(html`
  <div>Hello world</div>
`);

Using directly from Internals:

import { Internals } from 'diffhtml';

// This is the raw parse function which allows you to map dynamic values
// to either a TAG, ATTRIBUTE, or CHILD. You can find more information
// about this in the dynamic values section below.
console.log(Internals.parse(`
  <div>Hello world</div>
`));


Options

The parser is somewhat configurable, allowing you to opt into a strict-mode for erroring if invalid markup is passed. This could be useful to pair with the HTML Linter Middleware .


Strict mode

By default the parser operates in loose-mode which is forgiving of missing closing tags, poor markup, and other common issues. When opting into strict mode you will receive errors if you don't properly self close tags, have mismatched tag names, etc.

import { innerHTML } from 'diffhtml';

const options = {
  parser: {
    strict: true,
  }
};

// Will be fine since the elements match
innerHTML(document.body, `
  <h1>Hello world</h1>
`, options);

// Will throw since the elements do not match
innerHTML(document.body, `
  <h1>Hello world</h2>
`, options);

Unlike the other two options below, this feature can be configured using the tagged template html directly.

import { html } from 'diffhtml';

// Will throw an error due to the tag mismatch
html.strict`
  <p></div>
`;


Raw elements

A list of elements that have their contents treated as raw text, rather than parsed as HTML. You can provide your own list of element names to allow this feature.

Examples of these kinds of elements are: <pre>, <code>, <script>, <style>


Self closing elements

A list of elements that are allowed to self close. You can provide your own list of element names to allow this feature.

Examples of these kinds of elements are: <meta/>, <hr/>, <img/>


Dynamic values

The parser allows you to use dynamic values for many different parts of the HTML syntax.

You can put dynamic values in either: tag, attribute, or children locations. This makes it incredibly easy to compose dynamic template-driven UIs from your JavaScript view layer.

<TAG ATTRIBUTE>CHILDREN</TAG>

Internally diffHTML has the notion of a Supplemental object. This object contains three keys: tags, attributes, children.

In order to indicate that a given position should be swapped with a dynamic value simply use the syntax: __DIFFHTML__TOKEN__. Where the TOKEN value is an arbitrary string value that will correlate to a value provided to the parser. Every token must be completely unique. You cannot guarentee that the parser won't try to determine automatically what type the token belongs to. If a value is not found for the token, it will be left in your source.

An example setting each type of injection:

import { Internals, innerHTML } from 'diffhtml';

const vTree = Internals.parse(`
  <__DIFFHTML__TOKEN_0__ style=__DIFFHTML__TOKEN_1__>__DIFFHTML__TOKEN_2__</div>
`, {
  tags: {
    'TOKEN_0': 'div',
  },
  attributes: {
    'TOKEN_1': { fontWeight: 'bold' },
  },
  children: {
    'TOKEN_2': 'Custom style object',
  },
});

innerHTML(document.body, vTree);
Edit on GitHub