/h-include

Declarative client-side inclusion for the Web, using Custom Elements

Primary LanguageJavaScript

h-include.js

Declarative client-side transclusion. Perfect for Microfrontend architectures, in combination with server-side transclusion technologies like Edge-Side Includes.

Based on hinclude.js by @mnot.

Breaking change in version 2.0: changed configuration mechanism to use JavaScript instead of meta tag.

Usage

Include a document

<h-include src="/other/document/here.html"></h-include>

Include a document and extract a fragment

<h-include src="..." fragment=".container"></h-include>

Enable XMLHttpRequest.withCredentials

<h-include src="..." with-credentials></h-include>

Refresh an h-include element

document.getElementsByTagName('h-include')[0].refresh()

Rendering Mode

By default, each include is fetched in the background and the page is updated only when they all are available.

This is bounded by a timeout, by default 2500 ms. After the timeout, h-include will show what it has and keep on listening for the remaining responses.

However, it's also possible to have h-includes become visible as they're available, see the configuration section below. While this shows the included content quicker, it may be less visually smooth.

Other features

  • Media query support
  • Easy to inherit to create lazy loaded includes
  • Changing the @src attribute works as expected and includes a new resource

See the demo page for more documentation and examples.

Configuration

Set buffered include timeout (default is 2500 ms):

HIncludeConfig = { timeout: 10000 };

Set include mode to async (default is buffered):

HIncludeConfig = { mode: 'async' };

Throw if caught in an infinite include loop, to avoid the Droste effect:

HIncludeConfig = { checkRecursion: true };

Installation

Install using npm:

$ npm install h-include

Install using bower:

$ bower install h-include

Dependencies

h-include provides a custom element <h-include>. This means that you have to use a polyfill for enabling W3C Custom Elements for browsers not supporting it.

We recommend using document-register-element (3KB) as the polyfill for W3C Custom Elements.

Overridable function on the custom element

Function Arguments Default behavior Example override use case
createContainer request Creates a DOM container from the request Loop through links to resources and replace relative URLs with absolute URLs
extractFragment container, fragment, request Queries the container with a fragment selector. The default fragment selector is 'body'. Improved error handling if fragment doesn't match
replaceContent fragmentElement Replaces the innerHTML of the element with the innerHTML of the fragmentElement DOM diffing
onEnd request Add status information to the @class attribute of the h-include element

Override one or many functions by inheriting from the custom element, like this:

var proto = Object.create(HIncludeElement.prototype);

proto.onEnd = function(req){
  HIncludeElement.prototype.onEnd.apply(this, arguments); // call super

  // your code here
}

document.registerElement('h-include-improved', {
  prototype: proto,
});

Lazy loading example

This example uses the Intersection Observer API in a load event handler on window, to lazy-load <h-include-lazy> element content.

window.addEventListener('load', function() {
  var elements = document.getElementsByTagName('h-include-lazy');
  var config = {
    rootMargin: '400px 0px',
    threshold: 0.01 // 1% of the target is visible
  };

  var observer = new IntersectionObserver(onIntersection, config);
  [].forEach.call(elements, element => {
    observer.observe(element);
  });

  function onIntersection(entries) {
    entries.forEach(entry => {
      if (entry.intersectionRatio > 0) {
        observer.unobserve(entry.target);
        entry.target.refresh();
      }
    });
  }
});

var proto = Object.create(HIncludeElement.prototype);

proto.attachedCallback = function(){}

document.registerElement('h-include-lazy', {
  prototype: proto,
});

Media query support

It's possible to use media queries to have different fragments for different devices:

<h-include media="screen and (max-width: 600px)" src="small.html"></h-include>
<h-include media="screen and (min-width: 601px)" src="large.html"></h-include>

Navigation

Add navigate attribute to let link navigation events be captured by h-include element itself, which changes the src attribute and triggers a refresh.

If navigate attribute is used, use target="_top" to let link inside h-include behave as a normal link.

Error Handling

If fetching the included URL results in a 404 Not Found status code, the class of the include element will be changed to include_404. Likewise, a 500 Server Error status code will result in the include element’s class being changed to include_500.

Browser support

All modern browsers and IE down to IE10 are supported. If you find something quirky, please file an issue.

On HTTP/2

Browsers with HTTP/2 are using HTTP/2 for xhr requests as well. So, if both the server and the current browser supports HTTP/2, all requests made with h-include will go through the same TCP connection, given that they have the same origin.

FAQ

Please see the FAQ for some frequently asked questions.