1 | > ## 🛠 Status: Moved to `lit-element`
|
2 | > LitElement is currently in development. It's on the fast track to a 1.0 release, so we encourage you to use it and give us your feedback, but there are things that haven't been finalized yet and you can expect some changes.
|
3 |
|
4 | # LitElement
|
5 |
|
6 | [![Published on npm](https://img.shields.io/npm/v/@polymer/lit-element.svg)](https://www.npmjs.com/package/@polymer/lit-element)
|
7 | [![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/@polymer/lit-element)
|
8 | [![Mentioned in Awesome lit-html](https://awesome.re/mentioned-badge.svg)](https://github.com/web-padawan/awesome-lit-html)
|
9 |
|
10 | ## A simple base class for creating fast, lightweight web components
|
11 |
|
12 | LitElement uses [lit-html](https://github.com/Polymer/lit-html) to render into the
|
13 | element's [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM)
|
14 | and adds API to help manage element properties and attributes. LitElement reacts to changes in properties
|
15 | and renders declaratively using `lit-html`. See the [lit-html guide](https://lit-html.polymer-project.org/guide)
|
16 | for additional information on how to create templates for lit-element.
|
17 |
|
18 | * **Setup properties:** LitElement supports observable properties that cause the element to update.
|
19 | These properties can be declared in a few ways:
|
20 |
|
21 | * As class fields with the `@property()` [decorator](https://github.com/tc39/proposal-decorators#decorators),
|
22 | if you're using a compiler that supports them, like [TypeScript](https://www.typescriptlang.org/) or [Babel](https://babeljs.io/docs/en/babel-plugin-proposal-decorators).
|
23 | * With a static `properties` getter.
|
24 | * By manually writing getters and setters. This can be useful if tasks should
|
25 | be performed when a property is set, for example validation. Call `requestUpdate(name, oldValue)`
|
26 | in the setter to trigger an update and use any configured property options.
|
27 |
|
28 | Properties can be given an `options` argument which is an object that describes how to
|
29 | process the property. This can be done either in the `@property({...})` decorator or in the
|
30 | object returned from the `properties` getter, e.g. `static get properties { return { foo: {...} }`.
|
31 |
|
32 | Property options include:
|
33 |
|
34 | * `attribute`: Indicates how and whether the property becomes an observed attribute.
|
35 | If the value is `false`, the property is not added to the static `observedAttributes` getter.
|
36 | If `true` or absent, the lowercased property name is observed (e.g. `fooBar` becomes `foobar`).
|
37 | If a string, the string value is observed (e.g `attribute: 'foo-bar'`).
|
38 | * `converter`: Indicates how to convert the attribute to/from a property.
|
39 | The value can be a function used for both serialization and deserialization, or it can
|
40 | be an object with individual functions via the optional keys, `fromAttribute` and `toAttribute`.
|
41 | A default `converter` is used if none is provided; it supports
|
42 | `Boolean`, `String`, `Number`, `Object`, and `Array`.
|
43 | * `type`: Indicates the type of the property. This is used only as a hint for the
|
44 | `converter` to determine how to convert the attribute
|
45 | to/from a property. Note, when a property changes and the converter is used
|
46 | to update the attribute, the property is never updated again as a result of
|
47 | the attribute changing, and vice versa.
|
48 | * `reflect`: Indicates whether the property should reflect to its associated
|
49 | attribute (as determined by the attribute option). If `true`, when the
|
50 | property is set, the attribute which name is determined according to the
|
51 | rules for the `attribute` property option will be set to the value of the
|
52 | property converted using the rules from the `type` and `converter`
|
53 | property options.
|
54 | * `hasChanged`: A function that indicates whether a property should be considered
|
55 | changed when it is set and thus result in an update. The function should take the
|
56 | `newValue` and `oldValue` and return `true` if an update should be requested.
|
57 |
|
58 | * **React to changes:** LitElement reacts to changes in properties and attributes by
|
59 | asynchronously rendering, ensuring changes are batched. This reduces overhead
|
60 | and maintains consistent state.
|
61 |
|
62 | * **Declarative rendering** LitElement uses `lit-html` to declaratively describe
|
63 | how an element should render. Then `lit-html` ensures that updates
|
64 | are fast by creating the static DOM once and smartly updating only the parts of
|
65 | the DOM that change. Pass a JavaScript string to the `html` tag function,
|
66 | describing dynamic parts with standard JavaScript template expressions:
|
67 |
|
68 | * static elements: ``` html`<div>Hi</div>` ```
|
69 | * expression: ``` html`<div>${this.disabled ? 'Off' : 'On'}</div>` ```
|
70 | * property: ``` html`<x-foo .bar="${this.bar}"></x-foo>` ```
|
71 | * attribute: ``` html`<div class="${this.color} special"></div>` ```
|
72 | * boolean attribute: ``` html`<input type="checkbox" ?checked=${checked}>` ```
|
73 | * event handler: ``` html`<button @click="${this._clickHandler}"></button>` ```
|
74 |
|
75 | ## Getting started
|
76 |
|
77 | * The easiest way to try out LitElement is to use one of these online tools:
|
78 |
|
79 | * Runs in all [supported](#supported-browsers) browsers: [Glitch](https://glitch.com/edit/#!/hello-lit-element?path=index.html)
|
80 |
|
81 | * Runs in browsers with [JavaScript Modules](https://caniuse.com/#search=modules): [JSFiddle](https://jsfiddle.net/rzhofu81/), [JSBin](http://jsbin.com/vecuyan/edit?html,output),
|
82 | [CodePen](https://codepen.io/sorvell/pen/RYQyoe?editors=1000).
|
83 |
|
84 | * You can also copy [this HTML file](https://gist.githubusercontent.com/sorvell/48f4b7be35c8748e8f6db5c66d36ee29/raw/2427328cf1ebae5077902a6bff5ddd8db45e83e4/index.html) into a local file and run it in any browser that supports [JavaScript Modules]((https://caniuse.com/#search=modules)).
|
85 |
|
86 | * When you're ready to use LitElement in a project, install it via [npm](https://www.npmjs.com/). To run the project in the browser, a module-compatible toolchain is required. We recommend installing the [Polymer CLI](https://github.com/Polymer/polymer-cli) and using its development server as follows.
|
87 |
|
88 | 1. Add LitElement to your project:
|
89 |
|
90 | ```npm i @polymer/lit-element```
|
91 |
|
92 | 1. Install the webcomponents polyfill. If you're developing a reusable package, this should be a dev dependency which you load in your tests, demos, etc.
|
93 |
|
94 | ```npm i -D @webcomponents/webcomponentsjs```
|
95 |
|
96 |
|
97 | 1. Create an element by extending LitElement and calling `customElements.define` with your class (see the examples below).
|
98 |
|
99 | 1. Install the Polymer CLI:
|
100 |
|
101 | ```npm i -g polymer-cli```
|
102 |
|
103 | 1. Run the development server and open a browser pointing to its URL:
|
104 |
|
105 | ```polymer serve```
|
106 |
|
107 | > LitElement is published on [npm](https://www.npmjs.com/package/@polymer/lit-element) using JavaScript Modules.
|
108 | This means it can take advantage of the standard native JavaScript module loader available in all current major browsers.
|
109 | >
|
110 | > However, since LitElement uses npm convention to reference dependencies by name, a light transform to rewrite specifiers to URLs is required to get it to run in the browser. The polymer-cli's development server `polymer serve` automatically handles this transform.
|
111 |
|
112 | Tools like [WebPack](https://webpack.js.org/) and [Rollup](https://rollupjs.org/) can also be used to serve and/or bundle LitElement.
|
113 |
|
114 |
|
115 | ## Minimal Example
|
116 |
|
117 | 1. Create a class that extends `LitElement`.
|
118 | 1. Use a `@property` decorator to create a property (or implement a static `properties`
|
119 | getter that returns the element's properties). (which automatically become observed attributes).
|
120 | 1. Then implement a `render()` method and use the element's
|
121 | current properties to return a `lit-html` template result to render
|
122 | into the element.
|
123 |
|
124 | ```html
|
125 | <script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
|
126 | <script type="module">
|
127 | import {LitElement, html} from '@polymer/lit-element';
|
128 |
|
129 | class MyElement extends LitElement {
|
130 |
|
131 | static get properties() {
|
132 | return {
|
133 | mood: {type: String}
|
134 | };
|
135 | }
|
136 |
|
137 | constructor() {
|
138 | super();
|
139 | this.mood = 'happy';
|
140 | }
|
141 |
|
142 | render() {
|
143 | return html`<style> .mood { color: green; } </style>
|
144 | Web Components are <span class="mood">${this.mood}</span>!`;
|
145 | }
|
146 |
|
147 | }
|
148 |
|
149 | customElements.define('my-element', MyElement);
|
150 | </script>
|
151 |
|
152 | <my-element mood="happy"></my-element>
|
153 | ```
|
154 |
|
155 | ## API Documentation
|
156 |
|
157 | * `render()` (protected): Implement to describe the element's DOM using `lit-html`. Ideally,
|
158 | the `render` implementation is a [pure function](https://en.wikipedia.org/wiki/Pure_function) using only the element's current properties to describe the element template. Note, since
|
159 | `render()` is called by `update()`, setting properties does not trigger an
|
160 | update, allowing property values to be computed and validated.
|
161 |
|
162 | * `shouldUpdate(changedProperties)` (protected): Implement to control if updating and rendering
|
163 | should occur when property values change or `requestUpdate()` is called. The `changedProperties`
|
164 | argument is a Map with keys for the changed properties pointing to their previous values.
|
165 | By default, this method always returns `true`, but this can be customized as
|
166 | an optimization to avoid updating work when changes occur, which should not be rendered.
|
167 |
|
168 | * `performUpdate()` (protected): Implement to control the timing of an update, for example
|
169 | to integrate with a scheduler. If a Promise is returned from `performUpdate` it will be
|
170 | awaited before finishing the update.
|
171 |
|
172 | * `update(changedProperties)` (protected): This method calls `render()` and then uses `lit-html`
|
173 | in order to render the template DOM. It also updates any reflected attributes based on
|
174 | property values. Setting properties inside this method will *not* trigger another update.
|
175 |
|
176 | * `firstUpdated(changedProperties)`: (protected) Called after the element's DOM has been
|
177 | updated the first time, immediately before `updated()` is called.
|
178 | This method can be useful for capturing references to rendered static nodes that
|
179 | must be directly acted upon, for example in `updated()`.
|
180 | Setting properties inside this method will trigger the element to update.
|
181 |
|
182 | * `updated(changedProperties)`: (protected) Called whenever the element's DOM has been
|
183 | updated and rendered. Implement to perform post updating tasks via DOM APIs, for example,
|
184 | focusing an element. Setting properties inside this method will trigger the element to update.
|
185 |
|
186 | * `updateComplete`: Returns a Promise that resolves when the element has completed
|
187 | updating. The Promise value is a boolean that is `true` if the element completed the
|
188 | update without triggering another update. The Promise result is `false` if a
|
189 | property was set inside `updated()`. This getter can be implemented to await additional state.
|
190 | For example, it is sometimes useful to await a rendered element before fulfilling
|
191 | this Promise. To do this, first await `super.updateComplete` then any subsequent state.
|
192 |
|
193 | * `requestUpdate(name?, oldValue?)`: Call to request the element to asynchronously
|
194 | update regardless of whether or not any property changes are pending. This should
|
195 | be called when an element should update based on some state not triggered
|
196 | by setting a property. In this case, pass no arguments. It should also be called
|
197 | when manually implementing a property setter. In this case, pass the property
|
198 | `name` and `oldValue` to ensure that any configured property options are honored.
|
199 | Returns the `updateComplete` Promise which is resolved when the update completes.
|
200 |
|
201 | * `createRenderRoot()` (protected): Implement to customize where the
|
202 | element's template is rendered by returning an element into which to
|
203 | render. By default this creates a shadowRoot for the element.
|
204 | To render into the element's childNodes, return `this`.
|
205 |
|
206 | ## Advanced: Update Lifecycle
|
207 |
|
208 | * A property is set (e.g. `element.foo = 5`).
|
209 | * If the property's `hasChanged(value, oldValue)` returns `false`, the element does not
|
210 | update. If it returns `true`, `requestUpdate()` is called to schedule an update.
|
211 | * `requestUpdate()`: Updates the element after awaiting a [microtask](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/) (at the end
|
212 | of the event loop, before the next paint).
|
213 | * `performUpdate()`: Performs the update, calling the rest of the update API.
|
214 | * `shouldUpdate(changedProperties)`: The update proceeds if this returns `true`, which
|
215 | it does by default.
|
216 | * `update(changedProperties)`: Updates the element. Setting properties inside this
|
217 | method will *not* trigger another update.
|
218 | * `render()`: Returns a `lit-html` TemplateResult (e.g. <code>html\`Hello ${world}\`</code>)
|
219 | to render element DOM. Setting properties inside this method will *not* trigger
|
220 | the element to update.
|
221 | * `firstUpdated(changedProperties)`: Called after the element is updated the first time,
|
222 | immediately before `updated` is called. Setting properties inside this method will
|
223 | trigger the element to update.
|
224 | * `updated(changedProperties)`: Called whenever the element is updated.
|
225 | Setting properties inside this method will trigger the element to update.
|
226 | * `updateComplete` Promise is resolved with a boolean that is `true` if the
|
227 | element is not pending another update, and any code awaiting the element's
|
228 | `updateComplete` Promise runs and observes the element in the updated state.
|
229 |
|
230 | ## Bigger Example
|
231 |
|
232 | Note, this example uses decorators to create properties. Decorators are a proposed
|
233 | standard currently available in [TypeScript](https://www.typescriptlang.org/) or [Babel](https://babeljs.io/docs/en/babel-plugin-proposal-decorators).
|
234 |
|
235 | ```ts
|
236 | import {LitElement, html, property} from '@polymer/lit-element';
|
237 |
|
238 | class MyElement extends LitElement {
|
239 |
|
240 | // Public property API that triggers re-render (synced with attributes)
|
241 | @property()
|
242 | foo = 'foo';
|
243 |
|
244 | @property({type: Number})
|
245 | whales = 5;
|
246 |
|
247 | constructor() {
|
248 | super();
|
249 | this.addEventListener('click', async (e) => {
|
250 | this.whales++;
|
251 | await this.updateComplete;
|
252 | this.dispatchEvent(new CustomEvent('whales', {detail: {whales: this.whales}}))
|
253 | });
|
254 | }
|
255 |
|
256 | // Render method should return a `TemplateResult` using the provided lit-html `html` tag function
|
257 | render() {
|
258 | return html`
|
259 | <style>
|
260 | :host {
|
261 | display: block;
|
262 | }
|
263 | :host([hidden]) {
|
264 | display: none;
|
265 | }
|
266 | </style>
|
267 | <h4>Foo: ${this.foo}</h4>
|
268 | <div>whales: ${'🐳'.repeat(this.whales)}</div>
|
269 | <slot></slot>
|
270 | `;
|
271 | }
|
272 |
|
273 | }
|
274 | customElements.define('my-element', MyElement);
|
275 | ```
|
276 |
|
277 | ```html
|
278 | <my-element whales="5">hi</my-element>
|
279 | ```
|
280 |
|
281 | ## Supported Browsers
|
282 |
|
283 | The last 2 versions of all modern browsers are supported, including
|
284 | Chrome, Safari, Opera, Firefox, Edge. In addition, Internet Explorer 11 is also supported.
|
285 |
|
286 | ## Known Issues
|
287 |
|
288 | * On very old versions of Safari (<=9) or Chrome (<=41), properties created for native
|
289 | platform properties like (`id` or `name`) may not have default values set in the element constructor.
|
290 | On these browsers native properties appear on instances and therefore their default value
|
291 | will overwrite any element default (e.g. if the element sets this.id = 'id' in the constructor,
|
292 | the 'id' will become '' since this is the native platform default).
|
293 |
|
\ | No newline at end of file |