├── .babelrc ├── .clang-format ├── .editorconfig ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── api.md ├── demo ├── clock.html └── clock.js ├── docs-src ├── guide │ ├── 01-getting-started.md │ ├── 02-writing-templates.md │ ├── 03-how-it-works.md │ └── index.md ├── index.css └── index.md ├── docs ├── .nojekyll ├── api │ ├── assets │ │ ├── css │ │ │ ├── main.css │ │ │ └── main.css.map │ │ ├── images │ │ │ ├── icons.png │ │ │ ├── icons@2x.png │ │ │ ├── widgets.png │ │ │ └── widgets@2x.png │ │ └── js │ │ │ ├── main.js │ │ │ └── search.js │ ├── classes │ │ ├── _lib_lit_extended_.booleanattributepart.html │ │ ├── _lib_lit_extended_.eventpart.html │ │ ├── _lib_lit_extended_.propertypart.html │ │ ├── _lit_html_.attributepart.html │ │ ├── _lit_html_.nodepart.html │ │ ├── _lit_html_.svgtemplateresult.html │ │ ├── _lit_html_.template.html │ │ ├── _lit_html_.templateinstance.html │ │ ├── _lit_html_.templatepart.html │ │ ├── _lit_html_.templateresult.html │ │ ├── _test_lib_deferred_.deferred.html │ │ └── _test_lib_test_async_iterable_.testasynciterable.html │ ├── index.html │ ├── interfaces │ │ ├── _lit_html_.multipart.html │ │ ├── _lit_html_.part.html │ │ └── _lit_html_.singlepart.html │ └── modules │ │ ├── _lib_async_append_.html │ │ ├── _lib_async_replace_.html │ │ ├── _lib_lit_extended_.html │ │ ├── _lib_repeat_.html │ │ ├── _lib_shady_render_.html │ │ ├── _lib_unsafe_html_.html │ │ ├── _lib_until_.html │ │ ├── _lit_html_.html │ │ ├── _test_lib_deferred_.html │ │ └── _test_lib_test_async_iterable_.html ├── guide │ ├── getting-started.html │ ├── how-it-works.html │ ├── index.html │ └── writing-templates.html ├── index.css ├── index.html └── prism.css ├── lit-html.umd.js ├── package-lock.json ├── package.json ├── src ├── lib │ ├── async-append.ts │ ├── async-replace.ts │ ├── lit-extended.ts │ ├── repeat.ts │ ├── shady-render.ts │ ├── unsafe-html.ts │ └── until.ts ├── lit-html.ts └── test │ ├── lib │ ├── async-append_test.ts │ ├── async-replace_test.ts │ ├── deferred.ts │ ├── lit-extended_test.ts │ ├── repeat_test.ts │ ├── shady-render_test.ts │ ├── test-async-iterable.ts │ ├── unsafe-html_test.ts │ └── until_test.ts │ └── lit-html_test.ts ├── test ├── index-polyserve.html ├── index.html └── shady.html ├── tools ├── custom_typings │ └── front-matter.d.ts ├── package-lock.json ├── package.json ├── src │ ├── serve-site.ts │ └── site.ts └── tsconfig.json ├── tsconfig.json ├── tslint.json └── wct.conf.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["es2015", {"modules": "umd"}] 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | AlignAfterOpenBracket: AlwaysBreak 3 | AllowAllParametersOfDeclarationOnNextLine: false 4 | AllowShortBlocksOnASingleLine: false 5 | AllowShortCaseLabelsOnASingleLine: false 6 | AllowShortFunctionsOnASingleLine: None 7 | AllowShortIfStatementsOnASingleLine: false 8 | AllowShortLoopsOnASingleLine: false 9 | BinPackArguments: false 10 | # This breaks async functions sometimes, see 11 | # https://github.com/Polymer/polymer-analyzer/pull/393 12 | # BinPackParameters: false 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 2 | # This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt 3 | # The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt 4 | # The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt 5 | # Code distributed by Google as part of the polymer project is also 6 | # subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt 7 | 8 | # Polymer EditorConfig 9 | 10 | root = true 11 | 12 | [*] 13 | charset = utf-8 14 | indent_size = 2 15 | indent_style = space 16 | trim_trailing_whitespace = true 17 | 18 | [*.md] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /lib/ 3 | 4 | /tools/node_modules/ 5 | /tools/lib/ 6 | 7 | # Compiler output 8 | /lit-html.d.ts 9 | /lit-html.js 10 | /lit-html.js.map 11 | /test/**/*.d.ts 12 | /test/**/*.js 13 | /test/**/*.js.map 14 | 15 | yarn.lock 16 | 17 | # Logs 18 | logs 19 | *.log 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | 24 | # Runtime data 25 | pids 26 | *.pid 27 | *.seed 28 | *.pid.lock 29 | 30 | # Optional npm cache directory 31 | .npm 32 | 33 | # bower_components for testing 34 | bower_components 35 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/github/lit-html/9f9c1786bf11254bc33f3d5e607b7af1353ccb52/.npmignore -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: required 3 | dist: trusty 4 | node_js: stable 5 | addons: 6 | firefox: latest 7 | chrome: stable 8 | cache: 9 | directories: 10 | - node_modules 11 | before_script: 12 | - npm run build 13 | script: 14 | - xvfb-run wct --npm 15 | - if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then wct -s 'windows 10/microsoftedge@15' -s 'macos 10.12/safari@10' --npm; fi 16 | env: 17 | global: 18 | - secure: mNT4DpaOzcY+Z8JmXhVdbYBRt1gJG7kVMfe0Kd3HSRwQwAltW1JWhnRWQgW526xi/EFuYkIy1Ec4Hhc0pZ+t+ngXrHgtVPV6te7nQzBhBUNFZv72nDagk8YxQBTcSHMEVRa7c4NXlCW66hM0WWDVy7PACs7NuGj25qegFUulbjNEmYfwF8VMsfyB8/X6NJff8ZQTWEACwODJIBY2l0ogxI2jbUjTnrVNvtjd4IV1gnmi2AvY0RwRs/grigP4oMPcD/5tleUBjlojqq3U/DjMCoaoCge7fPnRZ2O1GHVHPOlAlFWa6DGvsXBiPNqlzchAQtkCKCnNJ1xM8UNlR0EYQCWBSsXO+wmAFoB1UexumHObsaCzLTL2yYXByCzKVNlGkCMppZUp+b+T3Vu039TEF1dCXf4XpQOouNb9pdlR0tkWUOF08hENzeAkHBFO1nw3kt+smm/b/6QXHe0H+X2GN3uKRX/TMYYgR3cckD4cQ9DeaXlJ/6tJtoVkOyNLL1LOHVtS7MTL2oUBJnj29cjOaUoCg/aVEt+g7brysj8Eb7itZctc/GwL/cWqIIKCuUUAuRJYgrBx3AQH9GjMtNAsrMtoVEmcOIK1lBLLmeduZXDogTevTMbGtyToATAQbLX/a2TxUBM5AZLE/dMiUnmZMVEMZ4anp2VhrmzflrbRcBI= 19 | - secure: UMzIg/aYKoDeMQqDyXcxpX0a1gWwmtCo+tx1zF0xhyoEPz3DNNV7axdqnqhiU9jPf7T5mGK4WWNDYWeFKMooD9J2rCgSxOPZHNDpcwQlC7KNHMKHXlMPLDzh1XborrSABowwj+Osq2Nmy7u1+aRtJDpcZ/PrYpsdHOx1wp+8aeO7ho8IFtgtDbdoQ7NUHXA4JtmORq4DH5MFyetrU70JSjwziL1T7H3kHkstjptMx4b5VszepcwFqsYXX+l0LxD1xYPcSc0QanwThYJLJb1JQSkqaDVphrMo+p7XdDVva9ExXvWfMOwJDRBvYP24sqBcYHei78irCzMKnRrcENgSK7G185p+9v5eO7DPROw5jjBB+uxXO/B5C1j1D5I1I1AMeccZ8kaBlqJgxhtTha9fJkwiRzYBrgmSS6eTORWMClAY84RlOtB2pL6wkx+/3ffXqbfbSP/mstAF1VkGwfav/XaWp2kxI4prEJi45PR4+wigugLQB/pLvMdItfGxAJLs+npv+w5nM7I2hJVfwvbuPVtAlz9pcn70kHcMvQbXsmdUzV6Se467HuwtruVQEhE6X01AW35VHLQi1GBMG/0xird+6WFi26/zj08nZaetW6BKqodHVYmzrSs5L2OcelJmAOOY2JQwQO/7RJ6zzwWu5hNdAo8STDgyYRhbYFlTRjs= 20 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/). 7 | 8 | 12 | 13 | 14 | 15 | ## [0.9.0] - 2018-02-01 16 | 17 | * Refactored how template tags and `render()` are implemented so that all 18 | specialization of template syntax is done in tags, not `render()`, allowing 19 | for the mixining of templates of different syntaxes, and for hooks in 20 | `render()` to change templates before they're initially processed. 21 | * Added ShadyCSS support in lib/shady-render.js. It's exported render function 22 | will pass templates to ShadyCSS's `prepareTemplate()` function to process style 23 | tags and elements in the template for emulate CSS scoping. 24 | * lit-extended: Attribute bindings with a `?` suffix on the name now act as boolean 25 | attributes. The attribute will be removed for falsey values and set to `''` for 26 | truthy values, matching the HTML specification behavior for boolean attributes. 27 | * Fixed a bug where directives rendered incorrectly on AttributeParts and PropertyParts 28 | 29 | ## [0.8.0] - 2018-01-12 30 | 31 | * Allow all valid HTML attribute names, including emoji and Angular-style 32 | `(foo)=` and `[foo]=` names. 33 | * Drastically improved performance of the `repeat` directive. 34 | * Fixed an issue with expressions directly following elements. 35 | * Fixed numerous bugs with the `repeat` directive. 36 | * Performance improvements for template setup 37 | * Internal code cleanup 38 | * Support synchronous thenables 39 | * Added the `asyncAppend` and `asyncReplace` directives to handle async iterable values in expressions. 40 | 41 | ## [0.7.0] - 2017-10-06 42 | 43 | * Added the `svg` template tag for creating partial SVG content 44 | * Support for expressions inside tables and other elements with limited permitted content 45 | * Only remove whitespace between elements, or at the start or end of elements 46 | * Fixed bugs with rendering iterables 47 | * A few IE/Edge fixes. Closer to full support. 48 | 49 | ## [0.6.0] - 2017-09-01 50 | 51 | * Fixed removing event handlers when setting them to `undefined`. 52 | * Allow the text "{{}}" to appear in templates. 53 | * Optimized clearing of Parts. 54 | * Added `unsafeHTML()` directive to bind values as HTML source. 55 | * Optimizations, simplification and bug fixes of Array handling code. 56 | * Update to extension API: added partCallback parameter to `render()`. 57 | * Added the `directive()` decorator function to create directives. Functions values are no longer treated as directive by default, simplifying declarative event handlers. 58 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to lit-html 2 | 3 | Thank you for your interest in contributing to lit-html! 4 | 5 | There are many ways to contribute to lit-html project, and we have many different needs to be addressed. All contributions, from PRs to reports of successful usage, are appreciated and valuable. 6 | 7 | ## Code of Conduct 8 | 9 | We have a [Code of Conduct](https://github.com/Polymer/polymer/wiki/Code-of-Conduct), please follow it in all interactions with project maintainers and fellow users. 10 | 11 | ## Filing Issues 12 | 13 | Issues are one of the most important ways to contribute to lit-html. 14 | 15 | Please search though open and closed issues to see if a similar issue already exists. If not, open an issue and try to provide a minimal reproduction if you can. 16 | 17 | Occasionally we'll close issues if they appear stale or are too vague - please don't take this personally! Please feel free to re-open issues we've closed if there's something we've missed and they still need to be addressed. 18 | 19 | ## Pull Requests 20 | 21 | Pull requests are greatly appreciated! To ensure a smooth review process, please follow these steps: 22 | 23 | 1. Make sure there's an open issue that the PR addresses. Add "Fixes #(issue number)" to the PR description. 24 | 2. Please discuss the general shape of the change ahead of time. This can save much time for reviewers and submitters alike. Many ties there may be ideas on how to handle an issue that are not fully written out, and asking about it will bring out more details. 25 | 3. All PRs that change behavior or fix bugs should have new or updated tests. 26 | 4. Try to create a set of descriptive commits that each do one focused change. Avoid commits like "oops", and prefer commits like "Added method foo to Bar". 27 | 5. When addressing review comments, try to add new commits, rather than modifying previous commits. This makes it easier for reviewers to see what changed since the last review. `git commit --fixup {SHA}` is really useful for this. Obviously, requests like "Please rebase onto master" require changing commits. 28 | 6. If you [allow changes to be committed to your PR branches](https://help.github.com/articles/allowing-changes-to-a-pull-request-branch-created-from-a-fork/) we can fix some small things in the PR for you, speeding up the review process. This is especially useful if you're new to TypeScript and need help with type annotations. 29 | 30 | ## Code Style 31 | 32 | We follow the [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html), but there are a couple of points worth emphasizing: 33 | 34 | 1. Clear is better than clever. Optimize for simple, readable code first. 35 | 2. Prefer longer, more descriptive names, over shorter names. For most variables, minification means we don't pay for extra characters in production. 36 | 3. Always err on the side of too many comments. When commenting, "why" is more important than "what". 37 | 4. If you're tempted to add a "what" comment, see if you can't restructure the code and use more descritive names so that the comment is unneccessary. 38 | 39 | ## TypeScript 40 | 41 | We use TypeScript on lit-html in order to automatically check the code for type errors and document the types of fields and attributes for easier reading. If you don't know TypeScript, we hope it doesn't discourage you from contributing - TypeScript is a superset of JavaScript that focuses on adding type annotations. 42 | 43 | TypeScript is hopefully relatively easy to pick up, but if you have any problems we're more than happy to help. You can submit a pull request with type warnings and we'll either help you fix them, or if you allow commits to your PR branch, fix them for you. VS Code is a very nice IDE for TypeScript development if you care to try it. 44 | 45 | ## Contributor License Agreement 46 | 47 | You might notice our friendly CLA-bot commenting on a pull request you open if you haven't yet signed our CLA. We use the same CLA for all open-source Google projects, so you only have to sign it once. Once you complete the CLA, all your pull-requests will automatically get the `cla: yes` tag. 48 | 49 | If you've already signed a CLA but are still getting bothered by the awfully insistent CLA bot, it's possible we don't have your GitHub username or you're using a different email address. Check the [information on your CLA](https://cla.developers.google.com/clas) or see this help article on [setting the email on your git commits](https://help.github.com/articles/setting-your-email-in-git/). 50 | 51 | [Complete the CLA](https://cla.developers.google.com/clas) 52 | 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, The Polymer Authors. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /api.md: -------------------------------------------------------------------------------- 1 | ## API 2 | 3 | ### Function `html` 4 | 5 | `html(strings: TemplateStringsArray, ...expressions: any[]): TemplateResult` 6 | 7 | `html` is a template tag for [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals), which parses the literal as HTML and returns a `TemplateResult`. 8 | 9 | ### Class `TemplateResult` 10 | 11 | `TemplateResult` is a class that holds a `Template` object parsed from a template literal and the values from its expressions. 12 | 13 | * Property `template: Template` 14 | 15 | A reference to the parsed `Template` object. 16 | 17 | * Property `values: any[]` 18 | 19 | The values returned by the template literal's expressions. 20 | 21 | ### Function `render(result: TemplateResult, container: Element): void` 22 | 23 | Renders a `TemplateResult`'s template to an element using the result's values. For re-renders, only the dynamic parts are updated. 24 | 25 | ### Class `Template` 26 | 27 | * Property `element: HTMLTemplateElement` 28 | 29 | * Property `parts: Part[]` 30 | 31 | ### Class `TemplateInstance` 32 | 33 | * Property `template: Template` 34 | 35 | * Method `_createPart(templatePart: TemplatePart, node: Node): Part` 36 | 37 | Creates a new Part for the given TemplatePart. This allows TemplateInstances to customize what kind of Parts are created for a template. 38 | 39 | * Method `_createInstance(template: Template): TemplateInstance` 40 | 41 | A factory for template instances, called when creating nested templates. This should usually just return a new instance of the implementing class. 42 | 43 | ### Abstract Class `Part` 44 | 45 | A `Part` is a dynamic section of a `TemplateInstance`. It's value can be set to update the section. 46 | 47 | Parts are either single-valued or multi-valued. If they have a `size` property they are multi-valued and take an array of values along with an index of where to start reading in the array. 48 | 49 | Specially supported value types are `Node`, `Function`, and `TemplateResult`. 50 | 51 | * Optional Property `size: number` 52 | 53 | * Method `setValue(value: any | any[], startIndex?: number): void` 54 | 55 | Sets the value of this part. If the part is multi-value, `value` will be an array, and `startIndex` will be a number. 56 | -------------------------------------------------------------------------------- /demo/clock.html: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /demo/clock.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 4 | * This code may only be used under the BSD style license found at 5 | * http://polymer.github.io/LICENSE.txt 6 | * The complete set of authors may be found at 7 | * http://polymer.github.io/AUTHORS.txt 8 | * The complete set of contributors may be found at 9 | * http://polymer.github.io/CONTRIBUTORS.txt 10 | * Code distributed by Google as part of the polymer project is also 11 | * subject to an additional IP rights grant found at 12 | * http://polymer.github.io/PATENTS.txt 13 | */ 14 | 15 | 16 | import {html, render, svg} from '../lit-html.js'; 17 | 18 | /** 19 | * Adapted from the Ractive.js clock example: http://www.ractivejs.org/examples/clock/ 20 | */ 21 | export class LitClock extends HTMLElement { 22 | 23 | get date() { return this._date; } 24 | set date(v) { this._date = v; this.invalidate(); } 25 | 26 | constructor() { 27 | super(); 28 | this.attachShadow({mode: 'open'}); 29 | setInterval(() => { 30 | this.date = new Date(); 31 | }, 1000); 32 | } 33 | 34 | render() { 35 | return html` 36 | 84 |
85 | 86 | 87 | 88 | 90 | 91 | 92 | ${minuteTicks} 93 | ${hourTicks} 94 | 95 | 96 | 98 | 99 | 100 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 |
111 | `; 112 | } 113 | 114 | invalidate() { 115 | if (!this.needsRender) { 116 | this.needsRender = true; 117 | Promise.resolve().then(() => { 118 | this.needsRender = false; 119 | render(this.render(), this.shadowRoot); 120 | }); 121 | } 122 | } 123 | } 124 | customElements.define('lit-clock', LitClock); 125 | 126 | const minuteTicks = (() => { 127 | const lines = []; 128 | for (let i = 0; i < 60; i++) { 129 | lines.push(svg` 130 | 135 | `); 136 | } 137 | return lines; 138 | })(); 139 | 140 | const hourTicks = (() => { 141 | const lines = []; 142 | for (let i = 0; i < 12; i++) { 143 | lines.push(svg` 144 | 149 | `); 150 | } 151 | return lines; 152 | })(); 153 | -------------------------------------------------------------------------------- /docs-src/guide/01-getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Getting Started 3 | --- 4 | 5 | # Getting Started 6 | 7 | ## Installation 8 | 9 | ### npm 10 | 11 | lit-htm is distributed on npm, in the [lit-html package]. 12 | 13 | ``` 14 | npm install lit-html 15 | ``` 16 | 17 | ### unpkg.com 18 | 19 | lit-html is also loadable directly from the unpkg.com CDN: 20 | 21 | ```js 22 | import {html, render} from 'https://unpkg.com/lit-html/lib/lit-extended.js?module'; 23 | ``` 24 | 25 | ## Importing 26 | 27 | lit-html is written in and distributed as standard JavaScript modules. 28 | Modules are increasingly supported in JavaScript environments and are shipping in Chrome, Opera and Safari, and soon will be in Firefox and Edge. 29 | 30 | To use lit-html, import it via a path: 31 | 32 | ```js 33 | import {html, render} from './node_modules/lit-html/lib/lit-extended.js'; 34 | ``` 35 | 36 | The path to use depends on where you've installed lit-html to. Browsers only support importing other modules by path, not by package name, so without other tools involved, you'll have to use paths. 37 | 38 | If you use some tool than can convert package names into paths, then you can import by path: 39 | 40 | ```js 41 | import {html, render} from 'lit-html/lib/lit-extended.js'; 42 | ``` 43 | 44 | 45 | ### Why is lit-html distributed as JavaScript modules, not as XXX? 46 | 47 | Until modules arrived, browsers have not had a standard way to import code from code, and user-land module loaders or bundlers were required. Since there was no standard, competing formats multiplied. Often libraries will publish in a number of formats to support users of different tools, but this causes problems when a common library is depended on by many other intermediate libraries: If some of those intermediate libraries load format A, and others load format B, and yet others load format C, etc., then multiple copies are loaded cause bloat, performance slowdowns, and sometimes hard-to-find bugs. 48 | 49 | The only true solution is to have one canonical version of a library that all other libraries import. Since modules support is rolling out to browsers now, and moduels are very well supported by tools, it makes for that format to be modules. 50 | 51 | [lit-html package]: https://www.npmjs.com/package/lit-html 52 | -------------------------------------------------------------------------------- /docs-src/guide/02-writing-templates.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Writing Templates 3 | --- 4 | 5 | # Writing Templates 6 | 7 | This section covers writing lit-html templates 8 | 9 | ## lit-html or lit-extended 10 | 11 | One of the first choices to make is whether to choose core lit-html templates, or lit-extended templates. lit-extended offers a few conveniences and is particularly useful for custom elements. It adds: 12 | 13 | * Declarative property setting, using attribute syntax 14 | * Opt-in attribute setting with the `name$=${}` syntax 15 | * Opt-in boolean attributes with the `name?=${}` syntax 16 | * Declarative event handler support with the `on-*=${}` syntax 17 | 18 | You import the lit-extended `html` tag from `lib/lit-extended.js`: 19 | 20 | ```js 21 | import {html} from `lit-html/lib/lit-extended.js'; 22 | ``` 23 | 24 | Because of the usefulness of these additional features, lit-extended is recommended for most users. 25 | 26 | ## Thinking Functionally 27 | 28 | lit-html is ideal for use in a functional approach to describing UIs. If you think of UI as a function of data, commonly expressed as `UI = f(data)`, you can write lit-html templates that mirror this exactly: 29 | 30 | ```js 31 | let ui = (data) => html`...${data}...`; 32 | ``` 33 | 34 | This kind of function can be called any time data changes, and is extremely cheap to call. The only thing that lit-html does in the `html` tag is forward the arguments to the templates. 35 | 36 | When the result is rendered, lit only updates the expressions whose values have changed since the previous render. 37 | 38 | This leads to an easy to write and reason about model: always try to describe your UI as a simple function of the data it depends on, an avoid caching intermediate state, or doing manual DOM manipulation. lit-html will almost always be fast enough with the simplest description of your UI. 39 | 40 | ## Template Structure 41 | 42 | lit-html templates are parsed by the built-in HTML parser before any values are interpolated. This means that the required structure of templates is determined by the HTML specification, and expressions can only occur in certain places. 43 | 44 | The HTML parser in browsers never throws exceptions for malformed HTML. Instead, the specification defines how all malformed HTML cases are handled and what the resulting DOM should be. Most cases of malformed templates are not detectable by lit-html - the only side-effect will be that templates do not behave as you expected - so take extra care to properly structure templates. 45 | 46 | 47 | Follow these rules for well-formed templates: 48 | 49 | * Templates must be well-formed when all expressions are replaced by empty values. 50 | * Expressions can only occur in attribute-value and text-content positions 51 | * Expressions cannot appear where tag or attribute names would appear 52 | * Templates can have multiple top-level elements and text 53 | * Templates should not contain unclosed elements - they will be closed by the HTML parser 54 | 55 | ## Binding Types 56 | 57 | Expressions can occur only in attribute value or text content positions, but in lit-extended a few different binding types use expressions in attribute value positions. Each binding types supports different types of values. In total, theses are the types of bindings: 58 | 59 | * Attribute bindings: All values are converted to strings 60 | * Property bindings: Any type of value 61 | * Event handler bindings: Event handler functions only 62 | * Text content bindings: TemplateResults, Nodes. Other types converted to strings. 63 | 64 | ## Supported Types 65 | 66 | lit-html expressions accept a large range of value types. 67 | 68 | ### Primitive Values: String, Number, Boolean, null, undefined 69 | 70 | Primitives values are converted to strings when interpolated. They are checked for equality to the previous value so that the DOM is not updated if the value hasn't changed. 71 | 72 | ### TemplateResult 73 | 74 | Templates can be nested by passing a `TemplateResult` as a value of an expression: 75 | 76 | ```js 77 | const header = html`

Header

`; 78 | 79 | const page = html` 80 | ${header} 81 |

This is some text

82 | `; 83 | ``` 84 | 85 | ### Node 86 | 87 | Any DOM Node can be passed to a text position expression. The node is attached to the DOM tree at that point, and so removed from any current parent: 88 | 89 | ```js 90 | const div = document.createElement('div'); 91 | const page = html` 92 | ${div} 93 |

This is some text

94 | `; 95 | ``` 96 | 97 | ### Arrays / Iterables 98 | 99 | Arrays and Iterables of supported types are supported as well. They can be mixed values of different supported types. 100 | 101 | ```javascript 102 | const items = [1, 2, 3]; 103 | const render = () => html`items = ${items.map((i) => `item: ${i}`)}`; 104 | ``` 105 | 106 | ```javascript 107 | const items = { 108 | a: 1, 109 | b: 23, 110 | c: 456, 111 | }; 112 | const render = () => html`items = ${Object.entries(items)}`; 113 | ``` 114 | 115 | ### Promises 116 | 117 | Promises 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. 118 | 119 | ```javascript 120 | const render = () => html` 121 | The response is ${fetch('sample.txt').then((r) => r.text())}. 122 | `; 123 | ``` 124 | 125 | ## Conditionals: Ifs and Loops 126 | 127 | lit-html has no built-in control-flow constructs. Instead you use normal JavaScript expressions and statements: 128 | 129 | ### Ifs with ternary operators 130 | 131 | Ternary expressions are a great way to add inline-conditionals: 132 | 133 | ```js 134 | html` 135 | ${user.isloggedIn 136 | ? html`Welcome ${user.name}` 137 | : html`Please log in` 138 | } 139 | `; 140 | ``` 141 | 142 | ### Ifs with if-statements 143 | 144 | You can express conditional logic with if statements outside of a template to compute values to use inside of the template: 145 | 146 | ```js 147 | let userMessage; 148 | if (user.isloggedIn) { 149 | userMessage = html`Welcome ${user.name}`; 150 | } else { 151 | userMessage = html`Please log in`; 152 | } 153 | 154 | 155 | html` 156 | ${userMessage} 157 | ` 158 | ``` 159 | 160 | ### Loops with Array.map 161 | 162 | To render lists, `Array.map` can be used to transform a list of data into a list of templates: 163 | 164 | ```js 165 | html` 166 | 169 | `; 170 | ``` 171 | 172 | ### Looping statements 173 | 174 | ```js 175 | const itemTemplates = []; 176 | for (const i of items) { 177 | itemTemplates.push(html`
  • ${i}
  • `); 178 | } 179 | 180 | html` 181 | 184 | `; 185 | ``` 186 | 187 | ## Directives 188 | 189 | Directives are functions that can extend lit-html by directly interacting with the Part API. 190 | 191 | Directives 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: 192 | 193 | ```javascript 194 | html`
    ${directive((part) => { part.setValue('Hello')})}
    ` 195 | ``` 196 | 197 | The `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. 198 | 199 | Here's an example of a directive that takes a function, and evaluates it in a try/catch to implement exception safe expressions: 200 | 201 | ```javascript 202 | const safe = (f) => directive((part) => { 203 | try { 204 | return f(); 205 | } catch (e) { 206 | console.error(e); 207 | } 208 | }); 209 | ``` 210 | 211 | Now `safe()` can be used to wrap a function: 212 | 213 | ```javascript 214 | let data; 215 | const render = () => html`foo = ${safe(_=>data.foo)}`; 216 | ``` 217 | 218 | This example increments a counter on every render: 219 | 220 | ```javascript 221 | const render = () => html` 222 |
    223 | ${directive((part) => part.setValue((part.previousValue + 1) || 0))} 224 |
    `; 225 | ``` 226 | 227 | lit-html includes a few directives: 228 | 229 | #### `repeat(items, keyfn, template)` 230 | 231 | A loop that supports efficient re-ordering by using item keys. 232 | 233 | Example: 234 | 235 | ```javascript 236 | const render = () => html` 237 | 241 | `; 242 | ``` 243 | 244 | #### `until(promise, defaultContent)` 245 | 246 | Renders `defaultContent` until `promise` resolves, then it renders the resolved value of `promise`. 247 | 248 | Example: 249 | 250 | ```javascript 251 | const render = () => html` 252 |

    253 | ${until( 254 | fetch('content.txt').then((r) => r.text()), 255 | html`Loading...`)} 256 |

    257 | `; 258 | ``` 259 | 260 | #### `asyncAppend(asyncIterable)` and `asyncReplace(asyncIterable)` 261 | 262 | JavaScript 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. 263 | 264 | lit-html offers two directives to consume asynchronous iterators: 265 | 266 | * `asyncAppend` renders the values of an [async iterable](https://github.com/tc39/proposal-async-iteration), 267 | appending each new value after the previous. 268 | * `asyncReplace` renders the values of an [async iterable](https://github.com/tc39/proposal-async-iteration), 269 | replacing the previous value with the new value. 270 | 271 | Example: 272 | 273 | ```javascript 274 | 275 | const wait = (t) => new Promise((resolve) => setTimeout(resolve, t)); 276 | 277 | /** 278 | * Returns an async iterable that yields increasing integers. 279 | */ 280 | async function* countUp() { 281 | let i = 0; 282 | while (true) { 283 | yield i++; 284 | await wait(1000); 285 | } 286 | } 287 | 288 | render(html` 289 | Count: ${asyncReplace(countUp())}. 290 | `, document.body); 291 | ``` 292 | 293 | In the near future, `ReadableStream`s will be async iterables, enabling streaming `fetch()` directly into a template: 294 | 295 | ```javascript 296 | // Endpoint that returns a billion digits of PI, streamed. 297 | const url = 298 | 'https://cors-anywhere.herokuapp.com/http://stuff.mit.edu/afs/sipb/contrib/pi/pi-billion.txt'; 299 | 300 | const streamingResponse = (async () => { 301 | const response = await fetch(url); 302 | return response.body.getReader(); 303 | })(); 304 | render(html`π is: ${asyncAppend(streamingResponse)}`, document.body); 305 | ``` 306 | -------------------------------------------------------------------------------- /docs-src/guide/03-how-it-works.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: How it Works 3 | --- 4 | 5 | # How it Works 6 | 7 | `lit-html` utilizes some unique properties of JavaScript template literals and HTML `