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.
- Templates, Partials and Slots
- Slot Properties
- Nested Templates
- Remote Templates
- Partials API
- Isomorphic Rendering
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>
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>
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>
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.
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>
HTML Partials introduces a few new DOM properties for working with composition.
For the document object:
-
document.templatesReadyState
- (Much like thedocument.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. Sodocument.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>
; whiledocument.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>
, whiledocument.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>
, thenelement.template
should be a reference to the<template>
at themodule/temp
namespace;element.template.partials.default
should thus return an array like the above.
For the <partials-slot>
element:
<partials-slot>.slottedElements
- (Much like theHTMLSlotElement.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, providetrue
on the first parameter.
For slotted elements:
element.slotReference
- (Much like theSlottable.assignedSlot
property.) This property gives a reference to the<partials-slot>
element an element was assigned to.