---
title: "Client-side templating"
manual: "TYPO3 Explained"
version: "11.5"
permalink: "https://docs.typo3.org/permalink/t3coreapi:js-templating@11.5"
source: "ApiOverview/JavaScript/Templating/Index.rst"
rendered: "2026-10-21T15:30:00+00:00"
---

> [!WARNING]
> **Attention**
>
> TYPO3 v11 has reached end-of-life as of October 31th 2024 and
> is no longer being maintained. Use the version switcher on the top
> left of this page to select documentation for a supported version of TYPO3.
>
> Need more time before upgrading?
> You can purchase Extended Long Term Support (ELTS) for TYPO3 v11 here:
> [TYPO3 ELTS](https://typo3.com/services/extended-support-elts).

# Client-side templating {#js-templating}

To avoid custom jQuery template building a slim client-side templating
engine [lit-html](https://lit-html.polymer-project.org/) together with [lit-element](https://lit-element.polymer-project.org/) is used in the TYPO3 Core.

This templating engine supports conditions, iterations, events, virtual DOM,
data-binding and mutation/change detections in templates.

Individual client-side templates can be processed in JavaScript directly
using modern web technologies like [template-strings](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) and [template-elements](https://developer.mozilla.org/de/docs/Web/HTML/Element/template).

Rendering is handled by the AMD-modules [lit-html](https://lit-html.polymer-project.org/) and [lit-element](https://lit-element.polymer-project.org/).
Please consult the lit-html [template-reference](https://lit-html.polymer-project.org/guide/template-reference) and the [lit-element-guide](https://lit-element.polymer-project.org/guide) for more
information.

## Examples {#examples}

### Variable assignment {#variable-assignment}

```ts
import {html, render} from 'lit-html';

const value = 'World';
const target = document.getElementById('target');
render(html`<div>Hello ${value}!</div>`, target);
```

```html
<div>Hello World!</div>
```

Unsafe tags would have been encoded (e.g. `<b>World</b>`
as `&lt;b&gt;World&lt;/b&gt;`).

### Conditions and iteration {#conditions-and-iteration}

```ts
import {html, render} from 'lit-html';
import {classMap} from 'lit-html/directives/class-map.js';

const items = ['a', 'b', 'c']
const classes = { list: true };
const target = document.getElementById('target');
const template = html`
   <ul class=${classMap(classes)}">
   ${items.map((item: string, index: number): string => {
      return html`<li>#${index+1}: ${item}</li>`
   })}
   </ul>
`;
render(template, target);
```

```html
<ul class="list">
   <li>#1: a</li>
   <li>#2: b</li>
   <li>#3: c</li>
</ul>
```

The `${...}` literal used in template tags can basically contain any
JavaScript instruction - as long as their result can be casted to `string`
again or is of type `lit-html.TemplateResult`. This allows to
make use of custom conditions as well as iterations:

-   condition: `${condition ? thenReturn : elseReturn}`
-   iteration: `${array.map((item) => { return item; })}`

### Events {#events}

Events can be bound using the `@` attribute prefix.

```ts
import {html, render} from 'lit-html';

const value = 'World';
const target = document.getElementById('target');
const template = html`
   <div @click="${(evt: Event): void => { console.log(value); }}">
      Hello ${value}!
   </div>
`;
render(template, target);
```

The result won't look much different than the first example - however the
custom attribute `@click` will be transformed into an according event
listener bound to the element where it has been declared.

### Custom HTML elements {#custom-html-elements}

A web component based on the W3C custom elements ("web-components\_") specification
can be implemented using `lit-element`.

```ts
import {LitElement, html, customElement, property} from 'lit-element';

@customElement('my-element')
class MyElement extends LitElement {

 // Declare observed properties
 @property()
 value: string = 'awesome';

 // Avoid Shadow DOM so global styles apply to the element contents
 createRenderRoot(): Element|ShadowRoot {
   return this;
 }

 // Define the element's template
 render() {
   return html`<p>Hello ${this.value}!</p>`;
 }
}
```

```html
<my-element value="World"></my-element>
```

This is rendered as:

```html
<my-element value="World">
   <p>Hello world!</p>
</my-element>
```
