HTML Templates

W3C Editor's Draft

This version
http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html
Latest editor's draft
http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html
Previous version
none
Revision history
http://dvcs.w3.org/hg/webcomponents/log/tip/spec/templates/index.html
Participate
Discuss on public-webapps@w3.org (Web Applications Working Group)
File bugs (w3.org's Bugzilla)
Editors
Dimitri Glazkov, Google, <>
Rafael Weinstein, Google, <>

Abstract

This specification describes a method for declaring inert DOM subtrees in HTML and manipulating them to instantiate document fragments with identical contents.

Status of This Document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

This document was published by the Web Applications Working Group as an Editor's Draft. If you wish to make comments regarding this document, please send them to public-webapps@w3.org (subscribe, archives). All feedback is welcome.

Publication as an Editor's Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

Table of Contents

  1. 1 About this Document
  2. 2 Dependencies
  3. 3 Terminology
  4. 4 Introduction
    1. 4.1 Declare as Markup
    2. 4.2 Declare Document Fragments, not Strings
    3. 4.3 Declare Anything
    4. 4.4 Declare Anywhere
    5. 4.5 Limit External Effects
  5. 5 Definitions
  6. 6 The template element
  7. 7 Parsing HTML Templates
    1. 7.1 Clearing of the Stack Adjustments
    2. 7.2 Addition to the "in body" Insertion Mode
    3. 7.3 Addition to the "in table" Insertion Mode
    4. 7.4 Addition to the "in cell" Insertion Mode
    5. 7.5 Addition to the "in select" Insertion Mode
    6. 7.6 Template contents" Insertion Mode
  8. 8 Serializing HTML Templates
  9. 9 Rendering HTML Templates
  10. Acknowledgements

About this Document

All diagrams, examples, notes, are non-normative, as well as sections explicitly marked as non-normative. Everything else in this specification is normative.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the normative parts of this document are to be interpreted as described in RFC2119. For readability, these words do not appear in all uppercase letters in this specification.

To help with layering and to avoid circular dependencies between various parts of specification, this document consists of three consecutive narratives:

  1. setting up the stage for the specification,
  2. explaining of the conceptual model and algorithms behind it, and
  3. expressing this model with DOM interfaces and HTML elements.

In a sense, these parts can be viewed as math, which sets up the reasoning environment, physics, which is the theoretical reasoning about the concept, and mechanics, which is the is the practical application of this reasoning.

Any point, at which a conforming UA must make decisions about the state or reaction to the state of the conceptual model, is captured as algorithm. The algorithms are defined in terms of processing equivalence. The processing equivalence is a constraint imposed on the algorithm implementors, requiring the output of the both UA-implemented and the specified algorithm to be exactly the same for all inputs.

Dependencies

This document relies on the following specifications:

Terminology

The following terms are used throughout the specification:

Populate terminology section

DOM
The document object model
document
The Document Object Model's underlying document
node
Any DOM object that participates in a tree
document fragment
A DOM object that implements the DocumentFragment interface
element
A DOM object that implements the Element interface
DOM tree
Any tree, composed of DOM objects

Introduction

This section is non-normative.

Web developers commonly need to create a document fragment that they could later insert into the document. This document fragment could be a part of temporary structure that is used to quickly switch in and out parts of the document DOM as a reaction to some trigger, such as timer or user action. It could also be an intermediate structure that serves as a template and is populated with specific data, to then be cloned or moved into the document DOM.

Let's examine the desired properties of declaring document fragments and challenges of acquiring these properties.

Declare As Markup

A typical approach for creating temporary or intermediate DOM trees is to build them with DOM APIs:


var tree = document.createDocumentFragment();
// add tree nodes imperatively …
var div = tree.appendChild(document.createElement('div'));
// … and/or use strings and innerHTML.
div.innerHTML = '<a href="//example.com/link">LINK</a>';
// …

While achieving its objective, such code views the elements either as purely DOM objects or strings. Both of the perspectives are removed from the document's markup flow, with the DOM objects perspective being imperative and verbose, thus difficult to reason about without first executing code, and the strings perspective being a poor-man's bootstrap into the HTML parser.

Subsequently, a more elegant solution is necessary: something that allows developers declare arbitrary DOM subtrees in the document markup. Empirically, all widely used Web frameworks and toolkits attempt to solve this problem, whether by using the script element with a custom type or with the help of specially-named attributes.

Declare Document Fragments, not Strings

There are two approaches to parsing the document fragment declarations:

The "declaration-as-string" approach is convenient on the surface, since it allows delaying the tokenization of a document fragment until it needs to be instantiated. In turn, this opens opportunity for easy string matching to substitute some specially marked placeholders with the actual data when templating. However, the delay also introduces an unhappy side effect of only discovering whether a document fragment declaration is valid at runtime.

Additionally, should the Web developer require for declarations to nest—to provide the templating for two-dimensional data, for instance—things start falling apart quickly. To address this, one must contemplate drastic additions to HTML tokenization to keep track of the nesting level in the declaration. Alternatively, a distinct syntax for nested declarations could be introduced to differentiate the first level of nesting, with a special tokenization mode inside of the outer declaration.

These undesirable consequences force us to consider the "declaration-as-tokens" approach. This approach, while still requiring some changes to the HTML parsing, handles nested templates more gracefully, and ensures that construction of the declared document fragment happens while parsing the document.

Declare Anything

Attempting to declare arbitrary document fragments runs into the limitations on the context of the element, imposed by the HTML parser. For example, in order for a tr element to succeed in being inserted into a tree while parsing, its parent has to be either table, thead, tbody, or tfoot. Since the developers are creating these tree outside of a document, they have to work around these limitations by either:

Both solutions incur unnecessary costs: the former requires extra work to manage the transient contextualizing elements, and the latter takes us away from the declarative syntax. Thus, we must consider relaxing the HTML tree construction rules to allow context-free element insertion in certain cases.

Declare Anywhere

Whenever developers declare a document fragment, they may need to place it at to the site of its instantiation. For instance, if the tree is used as a template for repeating elements, it would make sense to place it at the insertion site for the repeating elements:


<!-- uses fictional syntax -->
<ul>
    <stuff-to-repeat>
        <li class="${importance}"><a href="${link}">${title}</a></li>
    </stuff-to-repeat>
</ul>

Once again, the developers run into HTML parser limitations. Consider this, slightly modified example:


<!-- uses fictional syntax -->
<select>
    <stuff-to-repeat>
        <option class="${importance}">${title}</option>
    </stuff-to-repeat>
</select>

According to HTML tree construction algorithm, the stuff-to-repeat element will be never inserted into the resulting document DOM tree, thus losing information about the presence of the declaration. Similarly to the "do-what-I-mean" situation, we must consider relaxing the HTML tree construction rules to allow the placement of document fragment tree declarations anywhere in the document.

Limit External Effects

One reason for creating a document fragment is to clone it multiple times to create repeating items that vary in some content, but have common basic structure of across all instances.

Then, a typical flow of processing steps involves using this DOM tree and its clones as intermediaries to populate the document:

  1. Create a prototype: a document fragment to serve as a template
  2. Instantiate the prototype: clone the fragment to create a template document fragment
  3. Poplate the template document fragment with data for this fragment
  4. Append the template document fragment to the document
  5. Instantiate the prototype: clone the document fragment to create a template document fragment
  6. Populate the template document fragment with data for that fragment

In these steps, developers typically assume that modifying these intermediate document fragments does not have any external effects. In other words, changes to elements or structure of a document fragment is not perceptible outside of this tree. For most elements, this condition is immediately satisfied, since most HTML elements do not have external effects, such as rendering or firing events, until they are in the document tree. However, a small set of HTML elements, such as those representing embedded content requires special treatment.

For example, if developers wish to automate the process of populating a newly cloned template in the processing steps above, they would opt to use some specially-marked placeholders as attribute or text node values in the document fragment:

<div class="comment">
    <img src="${avatar}">
    <div class="text">${text}</div>
</div>

Then, when populating the newly cloned template document fragment, the placeholders are replaced with the actual values. Unfortunately, the img element will likely attempt to update the image data as soon as its src attribute is set to any non-empty value. In the scenario above, this leads to an unintended effect of making server requests with the url of ${avatar} for first document fragment, and then all other instances that are cloned from it.

To enforce developers' assumption on external effects, a slightly different set of restrictions is needed for the elements in intermediate trees. These restrictions would make the elements in the intermediate trees appear inert, or lacking any externals effects that are perceptible outside of the intermediate trees.

Definitions

A template provides a method for declaring document fragments in HTML. The document fragment that is declared by a template is called template contents.

The template contents must be declared using the HTML syntax in an HTML document. Once parsed, the template contents must not be in the document tree.

All elements in template contents must be inert. An element is inert when modifying its attributes or contents does not trigger any effects that can be perceived outside of the tree, in which it participates.

Conversely, serializing a template must result in the template contents serialized as part of the HTML document.

The template element

The template element represents a template.

Context
Where flow content is expected
Content Model
Metadata content
Children
Anything as template contents
Content attributes
Global attributes
DOM Interface

interface HTMLTemplateElement : HTMLElement {
    readonly attribute DocumentFragment content;
}
        
Attributes
content of type DocumentFragment, read-only
Provides access to template contents

Prior to first access, the code property must be initialized in a way that is equivalent to processing these steps:

Input
TEMPLATE, the template
Output
CONTENTS, the template contents
  1. Let DOCUMENT be a new Document node that does not have a browsing context
  2. Mark DOCUMENT as an HTML document
  3. Let CONTENTS be a new DocumentFragment object whose node document is DOCUMENT

The cloning steps for the template template element must include the cloning of template contents.

Parsing HTML Templates

The parsing of templates is defined as a set of additions to the HTML parsing algorithm:

When parsing, the template node is in the special category and is inserted into document tree using template insertion algorithm, which must be equivalent to processsing these steps:

Input
TOKEN, the template start tag token
STACK, the stack of open elements
Output
None
  1. Let NODE be the the top item in STACK
  2. Let TEMPLATE be the result of Creating an element for the TOKEN
  3. Let CONTENTS be the result of initializing template contents of the TEMPLATE
  4. Append TEMPLATE to NODE
  5. Push CONTENTS onto the STACK

Clearing of the Stack Adjustments

When popping elements from the stack of open elements, a conforming UA must abort the following procedures when the current node is template:

  1. Clearing the stack back to a table context
  2. Clearing the stack back to a table body context
  3. Clearing the stack back to a table row context

Addition to the "in body" Insertion Mode

Just before the Any other start tag rule in the "in body" insertion mode, add the following rule:

A start tag whose tag name is "template"
Run these steps:
  1. Insert a marker at the end of the list of active formatting elements
  2. Insert new template HTML element
  3. Switch the insertion mode to "template contents"
An end tag whose name is "template"
If the stack of open elements does not have an element in scope with the same tag name as that of the token, then this is a parse error; ignore the token.
Otherwise, run these steps:
  1. Generate implied end tags
  2. If the current node is not an element with the same tag name as that of the token, then this is a parse error
  3. Pop elements from the stack of open elements until an element with the same tag name as the token has been popped from the stack
  4. Clear the list of active formatting elements up to the last marker
  5. Reset the insertion mode appropriately

Addition to the "in table" Insertion Mode

Just before the Anything else rule in the "in table" insertion mode, add the following rule:

A start tag whose tag name is "template"
Process the token using rules for the "in body" insertion mode

Addition to the "in cell" Insertion Mode

Just before the Anything else rule in the "in table" insertion mode, add the following rule:

An end tag whose tag name is "template"
Close the cell and reprocess the current token

Addition to the "in select" Insertion Mode

Just before the Anything else rule in the "in select" insertion mode, add the following rule:

A start tag whose tag name is "template"
Process the token using rules for the "in body" insertion mode
An end tag whose name is "template"
If the stack of open elements does not have an element in select scope with the same tag name as the token, this is a parse error.
Run these steps:
  1. Pop elements from the stack of open elements until a template element has been popped from the stack.
  2. Reset the insertion mode appropriately

"Template contents" Insertion Mode

When the user is to apply the rules for the "template contents" insertion mode, the user agent must handle the token as follows:

A character token that is one of U+0009 CHARACTER TABULATION, U+000A LINE FEED (LF), U+000C FORM FEED (FF), U+000D CARRIAGE RETURN (CR), or U+0020 SPACE
Insert the character into the current node
A comment token
Append a Comment node to the current node with the data attribute set to the data given in the comment token
A start tag whose name is one of: "caption", "col", "colgroup", "tbody", "tfoot", thead"
Switch the insertion mode to "in table" and reprocess the current token
A start tag whose name is one of: "tr"
Switch the insertion mode to "in table body" and reprocess the current token
A start tag whose name is one of: "td", "th"
Switch the insertion mode to "in row" and reprocess the current token
An end tag whose name is "template"
  1. Pop the current node off the stack of open elements
  2. Reset the insertion mode appropriately
An end-of-file token
Parse error
Run these steps:
  1. Pop the current node off the stack of open elements
  2. Reset the insertion mode appropriately and reprocess the token
Anything else
Switch the insertion mode to "in body" and reprocess the current token

Serializing HTML Templates

The serialization of HTML Templates is defined this addition to the HTML fragment serialization algorithm:

In the rule "If current node is an Element", just before the step of recursing into the algorithm, add this step

If current nodes in an Element
If current node is a template element, then set current node to template contents.

Rendering HTML Templates

The template element is not rendered by default. Since they are not part of the document, the template contents must not not rendered. The template element must behave as if it is hosting a shadow DOM subtree with no insertion points.

Acknowledgements

The template element was described by Ian Hickson in the XBL 2.0 specification, and this HTML Templates specification borrows most of semantics from there, applying them to the HTML realm.

Erik Arvidsson and Adam Klein worked closely with the editors to help identify requirements and use cases for the templates, producing the Model-driven Views library, which uses a template element extensively.

The editors would also like to thank Adam Barth, Henri Sivonen, and Tab Atkins for their useful comments and contributions to the specification.