{"id":15048284,"url":"https://github.com/github/lit-html","last_synced_at":"2025-10-04T08:31:22.709Z","repository":{"id":65974860,"uuid":"118840043","full_name":"github/lit-html","owner":"github","description":"HTML template literals in JavaScript","archived":true,"fork":true,"pushed_at":"2018-04-18T08:52:10.000Z","size":667,"stargazers_count":14,"open_issues_count":0,"forks_count":15,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-09-29T00:21:23.486Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"lit/lit","license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/github.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-01-25T00:30:45.000Z","updated_at":"2024-07-31T03:19:04.000Z","dependencies_parsed_at":"2023-02-19T18:01:05.854Z","dependency_job_id":null,"html_url":"https://github.com/github/lit-html","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/github%2Flit-html","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/github%2Flit-html/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/github%2Flit-html/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/github%2Flit-html/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/github","download_url":"https://codeload.github.com/github/lit-html/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235232487,"owners_count":18957057,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-24T21:10:16.782Z","updated_at":"2025-10-04T08:31:16.286Z","avatar_url":"https://github.com/github.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lit-html\nHTML templates, via JavaScript template literals\n\n[![Build Status](https://travis-ci.org/Polymer/lit-html.svg?branch=master)](https://travis-ci.org/Polymer/lit-html)\n\n## Overview\n\n`lit-html` lets you write [HTML templates](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template) with JavaScript [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals), and efficiently render and _re-render_ those templates to DOM.\n\n```javascript\nimport {html, render} from 'lit-html';\n\n// This is a lit-html template function. It returns a lit-html template.\nconst helloTemplate = (name) =\u003e html`\u003cdiv\u003eHello ${name}!\u003c/div\u003e`;\n\n// Call the function with some data, and pass the result to render()\n\n// This renders \u003cdiv\u003eHello Steve!\u003c/div\u003e to the document body\nrender(helloTemplate('Steve'), document.body);\n\n// This updates to \u003cdiv\u003eHello Kevin!\u003c/div\u003e, but only updates the ${name} part\nrender(helloTemplate('Kevin'), document.body);\n```\n\n`lit-html` provides two main exports:\n\n * `html`: A JavaScript [template tag](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals) used to produce a `TemplateResult`, which is a container for a template, and the values that should populate the template.\n * `render()`: A function that renders a `TemplateResult` to a DOM container, such as an element or shadow root.\n\n### Announcement at Polymer Summit 2017\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.youtube.com/watch?v=ruql541T7gc\"\u003e\n    \u003cimg src=\"https://img.youtube.com/vi/ruql541T7gc/0.jpg\" width=\"256\" alt=\"Efficient, Expressive, and Extensible HTML Templates video\"\u003e\n    \u003cbr\u003e\n    Efficient, Expressive, and Extensible HTML Templates video\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## Motivation\n\n`lit-html` has four main goals:\n\n1. Efficient updates of previously rendered DOM.\n2. Expressiveness and easy access to the JavaScript state that needs to be injected into DOM.\n3. Standard JavaScript without required build steps, understandable by standards-compliant tools.\n4. Very small size.\n\n## How it Works\n\n`lit-html` utilizes some unique properties of HTML `\u003ctemplate\u003e` elements and JavaScript template literals. So it's helpful to understand them first.\n\n### Tagged Template Literals\n\nA JavaScript template literal is a string literal that can have other JavaScript expressions embedded in it:\n\n```javascript\n`My name is ${name}.`\n```\n\nA _tagged_ template literal is prefixed with a special template tag function:\n\n```javascript\nlet name = 'Monica';\ntag`My name is ${name}.`\n```\n\nTags are functions of the form: `tag(strings, ...values)`, where `strings` is an immutable array of the literal parts, and values are the results of the embedded expressions.\n\nIn the preceding example, `strings` would be `['My name is ', '.']`, and `values` would be `['Monica']`.\n\n### HTML `\u003ctemplate\u003e` Elements\n\nA `\u003ctemplate\u003e` element is an inert tree of DOM (script don't run, images don't load, custom elements aren't upgraded, etc) that can be efficiently cloned. It's usually used to tell the HTML parser that a section of the document must not be instantiated when parsed, but by code at a later time, but it can also be created imperatively with `createElement` and `innerHTML`.\n\n### Template Creation\n\nThe first time `html` is called on a particular template literal it does one-time setup work to create the template. It joins all the string parts with a special placeholder, `\"{{}}\"`, then creates a `\u003ctemplate\u003e` and sets its `innerHTML` to the result. Then it walks the template's DOM and extracts the placeholder and remembers their location.\n\nEvery call to `html` returns a `TemplateResult` which contains the template created on the first call, and the expression values for the current call.\n\n### Template Rendering\n\n`render()` takes a `TemplateResult` and renders it to a DOM container. On the initial render it clones the template, then walks it using the remembered placeholder positions, to create `Part`s.\n\nA `Part` is a \"hole\" in the DOM where values can be injected. `lit-html` includes two type of parts by default: `NodePart` and `AttributePart`, which let you set text content and attribute values respectively. The `Part`s, container, and template they were created from are grouped together in an object called a `TemplateInstance`.\n\nRendering can be customized by providing alternate `render()` implementations which create different kinds of `TemplateInstances` and `Part`s, like `PropertyPart` and `EventPart` included in `lib/lit-extended.ts` which let templates set properties and event handlers on elements.\n\n## Performance\n\n`lit-html` is designed to be lightweight and fast (though performance benchmarking is just starting).\n\n * It utilizes the built-in JS and HTML parsers - it doesn't include any expression or markup parser of its own.\n * It only updates the dynamic parts of templates - static parts are untouched, not even walked for diffing, after the initial render.\n * It uses cloning for initial render.\n\nThis should make the approach generally fast and small. Actual science and optimization and still TODOs at this time.\n\n## Features\n\n### Simple expressions and literals\n\nAnything coercible to strings are supported:\n\n```javascript\nconst render = () =\u003e html`foo is ${foo}`;\n```\n\n### Attribute-value Expressions\n\n```javascript\nconst render = () =\u003e html`\u003cdiv class=\"${blue}\"\u003e\u003c/div\u003e`;\n```\n\n### SVG Support\n\nTo create partial SVG templates - template that will rendering inside and `\u003csvg\u003e` tag (in the SVG namespace), use the `svg` template tag instead of the `html` template tag:\n\n```javascript\nconst grid = svg`\n  \u003cg\u003e\n    ${[0, 10, 20].map((x) =\u003e svg`\u003cline x1=${x} y1=\"0\" x2=${x} y2=\"20\"/\u003e`)}\n    ${[0, 10, 20].map((y) =\u003e svg`\u003cline x1=\"0\" y1=${y} x2=\"0\" y2=${y}/\u003e`)}\n  \u003c/g\u003e\n`;\n```\n\n### Safety\n\nBecause `lit-html` templates are parsed before values are set, they are safer than generating HTML via string-concatenation. Attributes are set via `setAttribute()` and node text via `textContent`, so the structure of template instances cannot be accidentally changed by expression values, and values are automatically escaped.\n\n_TODO: Add sanitization hooks to disallow inline event handlers, etc._\n\n### Case-sensitive Attribute Names\n\nAttribute parts store both the HTML-parsed name and the raw name pulled from the string literal. This allows extensions, such as those that might set properties on elements using attribute syntax, to get case-sensitive names.\n\n```javascript\nconst render = () =\u003e html`\u003cdiv someProp=\"${blue}\"\u003e\u003c/div\u003e`;\nrender().template.parts[0].rawName === 'someProp';\n```\n\n### Arrays/Iterables\n\n```javascript\nconst items = [1, 2, 3];\nconst render = () =\u003e html`items = ${items.map((i) =\u003e `item: ${i}`)}`;\n```\n\n```javascript\nconst items = {\n  a: 1,\n  b: 23,\n  c: 456,\n};\nconst render = () =\u003e html`items = ${Object.entries(items)}`;\n```\n\n### Nested Templates\n\n```javascript\nconst header = html`\u003ch1\u003e${title}\u003c/h1\u003e`;\nconst render = () =\u003e html`\n  ${header}\n  \u003cp\u003eAnd the body\u003c/p\u003e\n`;\n```\n\n### Promises\n\nPromises are rendered when they resolve, leaving the previous value in place until they do. Races are handled, so that if an unresolved Promise is overwritten, it won't update the template when it finally resolves.\n\n```javascript\nconst render = () =\u003e html`\n  The response is ${fetch('sample.txt').then((r) =\u003e r.text())}.\n`;\n```\n\n### Directives\n\nDirectives are functions that can extend lit-html by directly interacting with the Part API.\n\nDirectives will usually be created from factory functions that accept some arguments for values and configuration. Directives are created by passing a function to lit-html's `directive()` function:\n\n```javascript\nhtml`\u003cdiv\u003e${directive((part) =\u003e { part.setValue('Hello')})}\u003c/div\u003e`\n```\n\nThe `part` argument is a `Part` object with an API for directly managing the dynamic DOM associated with expressions. See the `Part` API in api.md.\n\nHere's an example of a directive that takes a function, and evaluates it in a try/catch to implement exception safe expressions:\n\n```javascript\nconst safe = (f) =\u003e directive((part) =\u003e {\n  try {\n    return f();\n  } catch (e) {\n    console.error(e);\n  }\n});\n```\n\nNow `safe()` can be used to wrap a function:\n\n```javascript\nlet data;\nconst render = () =\u003e html`foo = ${safe(_=\u003edata.foo)}`;\n```\n\nThis example increments a counter on every render:\n\n```javascript\nconst render = () =\u003e html`\n  \u003cdiv\u003e\n    ${directive((part) =\u003e part.setValue((part.previousValue + 1) || 0))}\n  \u003c/div\u003e`;\n```\n\nlit-html includes a few directives:\n\n#### `repeat(items, keyfn, template)`\n\nA loop that supports efficient re-ordering by using item keys.\n\nExample:\n\n```javascript\nconst render = () =\u003e html`\n  \u003cul\u003e\n    ${repeat(items, (i) =\u003e i.id, (i, index) =\u003e html`\n      \u003cli\u003e${index}: ${i.name}\u003c/li\u003e`)}\n  \u003c/ul\u003e\n`;\n```\n\n#### `until(promise, defaultContent)`\n\nRenders `defaultContent` until `promise` resolves, then it renders the resolved value of `promise`.\n\nExample:\n\n```javascript\nconst render = () =\u003e html`\n  \u003cp\u003e\n    ${until(\n        fetch('content.txt').then((r) =\u003e r.text()),\n        html`\u003cspan\u003eLoading...\u003c/span\u003e`)}\n  \u003c/p\u003e\n`;\n```\n\n#### `asyncAppend(asyncIterable)` and `asyncReplace(asyncIterable)`\n\nJavaScript asynchronous iterators provide a generic interface for asynchronous sequential access to data. Much like an iterator, a consumer requests the next data item with a a call to `next()`, but with asynchronous iterators `next()` returns a `Promise`, allowing the iterator to provide the item when it's ready.\n\nlit-html offers two directives to consume asynchronous iterators:\n\n * `asyncAppend` renders the values of an [async iterable](https://github.com/tc39/proposal-async-iteration),\nappending each new value after the previous.\n * `asyncReplace` renders the values of an [async iterable](https://github.com/tc39/proposal-async-iteration),\nreplacing the previous value with the new value.\n\nExample:\n\n```javascript\n\nconst wait = (t) =\u003e new Promise((resolve) =\u003e setTimeout(resolve, t));\n\n/**\n * Returns an async iterable that yields increasing integers.\n */\nasync function* countUp() {\n  let i = 0;\n  while (true) {\n    yield i++;\n    await wait(1000);\n  }\n}\n\nrender(html`\n  Count: \u003cspan\u003e${asyncReplace(countUp())}\u003c/span\u003e.\n`, document.body);\n```\n\nIn the near future, `ReadableStream`s will be async iterables, enabling streaming `fetch()` directly into a template:\n\n```javascript\n// Endpoint that returns a billion digits of PI, streamed.\nconst url =\n    'https://cors-anywhere.herokuapp.com/http://stuff.mit.edu/afs/sipb/contrib/pi/pi-billion.txt';\n\nconst streamingResponse = (async () =\u003e {\n  const response = await fetch(url);\n  return response.body.getReader();\n})();\nrender(html`π is: ${asyncAppend(streamingResponse)}`, document.body);\n```\n\n### Composability\n\nThese features compose so you can render iterables of functions that return arrays of nested templates, etc...\n\n### Extensibility\n\n`lit-html` is designed to be extended by more opinionated flavors of template syntaxes. For instance, `lit-html` doesn't support declarative event handlers or property setting out-of-the-box. A layer on top can add that while exposing the same API, by implementing a custom `render()` function.\n\nSome examples of possible extensions:\n\n * Property setting: Attribute expressions in templates could set properties on node.\n * Event handlers: Specially named attributes can install event handlers.\n * HTML values: `lit-html` creates `Text` nodes by default. Extensions could allow setting `innerHTML`.\n\n## Status\n\n`lit-html` is very new, under initial development, and not production-ready.\n\n * It uses JavaScript modules, and there's no build set up yet, so out-of-the-box it only runs in Safari 10.1, Chrome 61, and Firefox 54 (behind a flag).\n * It has a growing test suite, but it has only been run manually on Chrome Canary, Safari 10.1 and Firefox 54.\n * Much more test coverage is needed for complex templates, especially template composition and Function and Iterable values.\n * It has not been benchmarked thoroughly yet.\n * The API may change.\n\nEven without a build configuration, `lit-html` minified with `babili` and gzipped measures in at less than 1.7k. We will strive to keep the size extremely small.\n\n## Benefits over HTML templates\n\n`lit-html` has basically all of the benefits of HTML-in-JS systems like JSX, like:\n\n### Lighter weight\n\nThere's no need to load an expression parser and evaluator.\n\n### Seamless access to data\n\nSince template literals are evaluated in JavaScript, their expressions have access to every variable in that scope, including globals, module and block scopes, and `this` inside methods.\n\nIf the main use of templates is to inject values into HTML, this breaks down a major barrier between templates and values.\n\n### Faster expression evaluation\n\nThey're just JavaScript expressions.\n\n### IDE support by default\n\nIn a type-checking environment like TypeScript, expressions are checked because they are just regular script. Hover-over docs and code-completion just work as well.\n\n### Case-sensitive parsing\n\nTemplate literals preserve case, even though the HTML parser doesn't for attribute names. `lit-html` extracts the raw attribute names, which is useful for template syntaxes that use attribute syntax to set properties on elements.\n\n## Benefits over JSX\n\n### Native syntax\n\nNo tooling required. Understood by all JS editors and tools.\n\n### No VDOM overhead\n\n`lit-html` only re-renders the dynamic parts of a template, so it doesn't produce a VDOM tree of the entire template contents, it just produces new values for each expression. By completely skipping static template parts, it saves work.\n\n### Scoped\n\nJSX requires that the compiler be configured with the function to compile tags to. You can't mix two different JSX configurations in the same file.\n\nThe `html` template tag is just a variable, probably an imported function. You can have any number of similar functions in the same JS scope, or set `html` to different implementations.\n\n### Templates are values\n\nJSX translates to function calls, and can't be manipulated on a per-template basis at runtime. `lit-html` produces a template object at runtime, which can be further processed by libraries like ShadyCSS.\n\n### CSS-compatible syntax\n\nBecause template literals use `${}` as the expression delimiter, CSS's use of `{}` isn't interpreted as an expression. You can include style tags in your templates as you would expect:\n\n```javascript\nhtml`\n  \u003cstyle\u003e\n    :host {\n      background: burlywood;\n    }\n  \u003c/style\u003e\n`\n```\n\n## Future Work\n\n### Higher-Order Templates examples\n\n#### `when(cond, then, else)`\n\nAn if-directive that retains the `then` and `else` _instances_ for fast switching between the two states, like `\u003cdom-if\u003e`.\n\nExample:\n\n```javascript\nconst render = () =\u003e html`\n  ${when(state === 'loading',\n    html`\u003cdiv\u003eLoading...\u003c/div\u003e`,\n    html`\u003cp\u003e${message}\u003c/p\u003e`)}\n`;\n```\n\n#### `guard(guardExpr, template)`\n\nOnly re-renders an instance if the guard expression has changed since the last render.\n\nSince all expressions in a template literal are evaluated when the literal is evaluated, you may want to only evaluate some expensive expressions when certain other values (probably it's dependencies change). `Guard` would memoize the function and only call it if the guard expression changed.\n\nExample:\n\n```javascript\nconst render = () =\u003e html`\n  \u003cdiv\u003eCurrent User: ${guard(user, () =\u003e user.getProfile())}\u003c/div\u003e\n`;\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgithub%2Flit-html","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgithub%2Flit-html","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgithub%2Flit-html/lists"}