HTML Partials

HTML Partials is a DOM feature that lets us define, import, access, and compose with reusable HTML snippets using the template, partials, and slots paradigm.

On this page:

Templates, Partials and Slots

A template is a collection of independent partials that can be consumed from anywhere in the main document.

<head>
<template name="template1">
<div id="partial-1"></div>
<div id="partial-2"></div>
</template>
</head>

An element in the main document, called the implementation block or the composition area, can define <partials-slot>s, and then, point to a <template> to have the template's partials mapped to its slots.

<html>
<head>
<template name="template1">
<div id="partial-2" partials-slot="slot-1"></div>
<div id="partial-2" partials-slot="slot-2"></div>
</template>
</head>
<body>
<div template="template1">
<h2>I have slots</h2>
<partials-slot name="slot-1"></partials-slot>
<div>
<partials-slot name="slot-2"></partials-slot>
</div>
</div>
</body>
</html>

Composition takes place and the slots are replaced by the template's partials. The block is said to have implemented the <template>.

<html>
<head>
<template name="template1">
<div id="partial-2" partials-slot="slot-1"></div>
<div id="partial-2" partials-slot="slot-2"></div>
</template>
</head>
<body>
<div template="template1">
<h2>I have slots</h2>
<div id="partial-2" partials-slot="slot-1"></div>
<div>
<div id="partial-2" partials-slot="slot-2"></div>
</div>
</div>
</body>
</html>

An implementation block can implement another <template> by simply pointing to it; <partials-slot>s are disposed off of their previous slotted contents and recomposed from the new <template>.

The <partials-slot> element, even though replaced, is never really destroyed. It returns to its exact position whenever the last of its slotted elements get deleted, or whenever the slot has no corresponding partial in the next implemented <template>.

HTML Partials also supports Default Slots. A template's direct children without an explicit partials-slot attribute are slotted into the Default Slot in the implementation block.

Universal Slots

By default, slots are scoped to their containing implementation block. But the <partials-slot> element may also be used independent of an implementation block to point to its own <template>.

<html>
<head>
<template name="template1">
<div partials-slot="slot-1"></div>
<div partials-slot="slot-2"></div>
</template>
<template name="template2">
<div partials-slot="slot-1"></div>
<div partials-slot="slot-2"></div>
</template>
</head>
<body>
<div template="template1">
<h2>I have slots</h2>
<partials-slot name="slot-1"></partials-slot>
<div>
<partials-slot name="slot-1" template="template2"></partials-slot>
</div>
</div>
<partials-slot name="slot-2" template="template1"></partials-slot>
</body>
</html>

Slot Properties

In HTML Partials, slots may be defined with extra properties that a slotted element can inherit. Every element slotted in its place will take on these properties.

Inherittable properties can be both attributes and content.

Attributes

A <partials-slot>'s attributes (other than the name and template attributes) are inheritted by every slotted element.

When a slotted element inherits attributes from a <partials-slot>, inheritted attributes are made to take priority over any existing attributes. On inheriting single-value attributes, like the id attribute, any such attribute is replaced on the slotted element. On inheriting space-delimitted attributes, like the class attribute, new and non-duplicate values are placed after any existing values on the slotted element. On inheriting key/value attributes, like the style attribute, new declarations are placed after any existing declarations on the slotted element (making CSS cascading work on the style attribute).

Below, we are using Slot Attributes inheritance to recompose the same partial differently on each slotting - to adapt it for each usecase.

<html>
<head>
<template name="template1">
<div partials-slot="slot-1"></div>
<div partials-slot="slot-2"></div>
</template>
</head>
<body>
<div template="template1">
<partials-slot name="slot-1" id="headline" style="color:red"></partials-slot>
</div>
<partials-slot name="slot-1" template="template1" style="color:blue"></partials-slot>
</body>
</html>

Content

Normally, a <partials-slot> can have default content that renders before slotting takes place. But this content can instead be defined as a new set of partials that can be implemented by slotted elements. This time, the <partials-slot> element gets to act as the <template> and the slotted element as the implementation block. (In the light/shadow terminology, this is the <partials-slot> element acting as an element's Light DOM and the slotted element as its Shadow DOM.)

To implement a <partials-slot>, a partial would set its template attribute to the keyword @slot instead of pointing to an actual <template> element.

<html>
<head>
<template name="template2">
<!-- I am a recomposable partial. My ideal slot provides the partials for me -->
<div partials-slot="slot-1" template="@slot">
<partials-slot name="slot-1-1"></partials-slot>
</div>
<!-- I am a regular partial -->
<div partials-slot="slot-2"></div>
</template>
</head>
<body>
<div template="template1">
<!-- I am an implementable slot. My ideal partial defines slots -->
<partials-slot name="slot-1">
<div partials-slot="slot-1-1"></div>
</partials-slot>
</div>
</body>
</html>

Nested Templates

Templates may be nested for organizational purposes.

<template name="template1">
<div partials-slot="slot1"></div>
<div partials-slot="slot2"></div>
<template name="nested1">
<div partials-slot="slot3"></div>
<div partials-slot="slot4"></div>
</template>
<template name="nested2">
<div partials-slot="slot5"></div>
<div partials-slot="slot6"></div>
</template>
</template>

Nested templates are referenced using a path notation:

<div template="template1/nested1">
</div>

Remote Templates

Templates may reference remote content using the src attribute.

Remote file: http://localhost/templates.html

<div partials-slot="slot-1"></div>
<div partials-slot="slot-2"></div>
<template name="extended">
<div partials-slot="slot-3"></div>
<div partials-slot="slot-4"></div>
</template>
<p></p>

Document: http://localhost

<head>
<template name="template1" src="/templates.html"></template>
</head>

Where remote templates are detected in a document, <partials-slot>s are resolved after all <template>s have loaded their content.

Isomorphic Rendering

When rendering happens on the server and has to be serialized for the browser to take over, the browser must still be able to maintain references to all <partials-slot>s, even those replaced on the server. HTML Partials addresses this by serializing <partials-slot> elements as comment nodes (<!-- <partials-slot></partials-slot> -->) with a view to recreating the original slot elements from these comments on getting to the browser. This way, composition is able to continue. Now in the browser, deleting a server-slotted element, for example, should trigger the restoration of the original <partials-slot> element; changing the template attribute of any element should dispose off all its server-slotted elements and recompose the block from the new referenced <template>.

Before Rendering on the Server

<html>
<head>
<template name="template2">
<div partials-slot="slot-1"></div>
<div partials-slot="slot-2"></div>
</template>
</head>
<body>
<div template="template1">
<partials-slot name="slot-1" id="headline" style="color:red">Default Headline</partials-slot>
</div>
<partials-slot template="template1" name="slot-1" style="color:blue"></partials-slot>
</body>
</html>

After Rendering on the Server

<html>
<head>
<template name="template2">
<div partials-slot="slot-1"></div>
<div partials-slot="slot-2"></div>
</template>
</head>
<body>
<div template="template1">
<div partials-slot="slot-1" id="headline" style="color:red"></div>
<!-- <partials-slot name="slot-1" id="headline" style="color:red">Default Headline</partials-slot> -->
</div>
<div partials-slot="slot-1" style="color:blue"></div>
<!-- <partials-slot template="template1" name="slot-1" style="color:blue"></partials-slot> -->
</body>
</html>

Now on the Browser

Find and delete the server-slotted element with ID #headline. The original <partials-slot> element should now be restored and ready to be replaced the next time composition takes place.

<html>
<head>
<template name="template2">
<div partials-slot="slot-1"></div>
<div partials-slot="slot-2"></div>
</template>
</head>
<body>
<div template="template1">
<partials-slot name="slot-1" id="headline" style="color:red">Default Headline</partials-slot>
<!-- <partials-slot name="slot-1" id="headline" style="color:red">Default Headline</partials-slot> -->
</div>
<div partials-slot="slot-1" style="color:blue"></div>
<!-- <partials-slot template="template1" name="slot-1" style="color:blue"></partials-slot> -->
</body>
</html>

Enabliing Slots Serialization

Since slots serialization is only necessary for isomorphic pages, this feature is designed to be explicitly turned on on the CHTML META tag.

<html>
<head>
<meta name="chtml" content="isomorphic=true;" />
</head>
<body></body>
</html>

Partials API

HTML Partials introduces a few new DOM properties for working with composition.

For the document object:

  • document.templatesReadyState - (Much like the document.readyState property.) This property reflects the document's loading status of remote templates:

    • loading - This is the initial value of this property.

    • complete - This is the value of this property when templates are done loading, or when there are no remote templates at all.

      When the state of this property changes, the templatesreadystatechange event is fired on the document object.

  • document.templates - This property represents the list of <template>s in the document. References to templates are maintained here by name. So document.templates.template1 should return the <template> element used in the examples above.

For the <template> element:

  • <template>.partials - This property represents the list of partials defined by the <template>. References to partials are maintained here by name. Unnamed partials are treated as having the name default. So, for the <template> below,

    <template name="template1">
    <div partials-slot="one"></div>
    <div partials-slot="two"></div>
    <div partials-slot="default"></div>
    <p></p>
    </template>

    accessing document.templates.template1.partials.one should return an array containing the first <div>; while document.templates.template1.partials.default should return an array containing the last <div> and <p>.

  • <template>.templates - This property represents the list of <template>s nested within the <template>. References to templates are maintained here by name.

    <template name="template1">
    <template name="nested1"></template>
    <template name="nested2">
    <div partials-slot="one"></div>
    </template>
    </template>

    accessing document.templates.template1.templates.nested1 should return the first nested <template>, while document.templates.template1.templates.nested2 the second nested <template>. And the nesting can go on as much as code organization requires.

For every element:

  • element.template - This property is a reference to the <template> element pointed to by an element. So if an element implements a template as in <div template="html/temp"></div>, then element.template should be a reference to the <template> at the module/temp namespace; element.template.partials.default should thus return an array like the above.

For the <partials-slot> element:

  • <partials-slot>.slottedElements - (Much like the HTMLSlotElement.assignedElements() method.) This property represents the list of partials slotted into a slot.

  • <partials-slot>.resolve() - This method, without arguments, is used to programatically resolve a <partials-slot> from the appropriate <template> given in context.

  • <slot>.empty([silently = false]) - This method is used to programatically empty the slot of its partials, thereby triggering the restoration of the <partials-slot> element itself. To empty the slot silently without restoring the original <partials-slot> element, provide true on the first parameter.

For slotted elements:

  • element.slotReference - (Much like the Slottable.assignedSlot property.) This property gives a reference to the <partials-slot> element an element was assigned to.