Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lit cheat sheet #1355

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./my-element.js"></script>

<my-element></my-element>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { html, LitElement, css } from 'lit';
import { customElement } from 'lit/decorators.js';

@customElement('my-element')
export class MyElement extends LitElement {
render() {
return html`<p>I'm blue</p><div>I'm red</div>`;
}

static styles = css`
p {
color: blue;
}
div {
color: red;
}
`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "/samples/v3-base.json",
"files": {
"my-element.ts": {},
"index.html": {}
},
"previewHeight": "100px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./my-element.js"></script>

<my-element></my-element>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { html as staticHTML, StaticValue } from 'lit/static-html.js';
import { live } from 'lit/directives/live.js';

@customElement('input-or-textfield')
export class MyElement extends LitElement {
// attribute is false because this is a value that can't be serialized to an
// HTML attribute
@property({ attribute: false }) tagLiteral: StaticValue|null = null;
@property() value = '';

render() {
return html`
${
// NOTE: the live() directive prevents setting the .value property if
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove live here and the comment. As long as the tag doesn't change, the expense is minimal.

// the live value of the input / textfield already matches this.value.
// This is important since static html templates should not be thrashed
// due to performance concerns.
staticHTML`
<${this.tagLiteral}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't this use unsafeStatic or literal?

@input=${this.#onInput}
.value=${live(this.value)}></${this.tagLiteral}>
`
}
<div>
The value of the input is: ${this.value}
</div>
`;
}

#onInput(e: InputEvent) {
this.value = (e.target as (HTMLInputElement | HTMLTextAreaElement)).value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { css, html, LitElement } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { literal } from 'lit/static-html.js';
import './input-or-textfield.js';

@customElement('my-element')
export class MyElement extends LitElement {
@state() tagLiteral = literal`input`;
render() {
return html`
<!-- /* playground-fold */ -->
<fieldset>
<legend>Choose a tag to render:</legend>
<div>
<label>
<input
type="radio"
name="selection"
@change=${this.#onChange}
value="input"
checked>
input
</label>
</div>
<div>
<label>
<input
type="radio"
name="selection"
@change=${this.#onChange}
value="textarea">
textarea
</label>
</div>
</fieldset>
<!-- /* playground-fold-end */ -->
<input-or-textfield
value="this is the default value"
.tagLiteral=${this.tagLiteral}>
</input-or-textfield>
`;
}

#onChange(e: InputEvent) {
const target = e.target as HTMLInputElement;
this.tagLiteral = target.value === 'input' ? literal`input` : literal`textarea`;
}

static styles = css`/* playground-fold */:host { font-family: sans-serif; } :host > * { margin-block: .5em; }/* playground-fold-end */`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "/samples/v3-base.json",
"files": {
"input-or-textfield.ts": {},
"my-element.ts": {},
"index.html": {}
},
"previewHeight": "175px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./my-element.js"></script>

<my-element></my-element>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { html, LitElement, css } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';

@customElement('my-element')
export class MyElement extends LitElement {
@state() counter = 0

firstUpdated() {
setInterval(() => this.counter += 1 , 1000);
}

render() {
const classes = {
red: this.counter % 2 === 0,
blue: this.counter % 2 === 1
};
return html`<p class=${classMap(classes)}>Hello!</p>`;
}

static styles = css`
.red {
color: red;
}
.blue {
color: blue;
}
`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "/samples/v3-base.json",
"files": {
"my-element.ts": {},
"index.html": {}
},
"previewHeight": "100px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./my-element.js"></script>

<my-element></my-element>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { html, LitElement } from 'lit';
import { customElement, state } from 'lit/decorators.js';

@customElement('my-element')
export class MyElement extends LitElement {
@state() private someBoolean = false;

render() {
let someText = html`<p>Some text</p>`;

if (this.someBoolean) {
someText = html`<p>Some other text</p>`;
}

return html`
<button
@click=${() => {this.someBoolean = !this.someBoolean}}>
Toggle template
</button>
<div>This is an inline ternary conditional</div>
${this.someBoolean ? html`<p>Some other text</p>` : html`<p>Some text</p>`}
<div>This is a variable conditional</div>
${someText}
`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "/samples/v3-base.json",
"files": {
"my-element.ts": {},
"index.html": {}
},
"previewHeight": "200px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./my-element.js"></script>

<my-element></my-element>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
import { trustedStyles, type CSSStyleSheet } from './trusted-stringified-css-source.js';

// Use constructable stylesheets on TRUSTED CSS strings to use them in a LitElement
const styles = new CSSStyleSheet();
// this type assertion is needed for the older version of TS like that the lit.dev website uses
(styles as unknown as CSSStyleSheet).replace(trustedStyles);

@customElement('my-element')
export class MyElement extends LitElement {
static styles = styles;
render() {
return html`
<div>
This should be red!
</div>
`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "/samples/v3-base.json",
"files": {
"my-element.ts": {},
"trusted-stringified-css-source.ts": {},
"index.html": {}
},
"previewHeight": "100px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const trustedStyles = `
div {
color: red;
}
`;

// This may be needed for some older versions of TS
export type CSSStyleSheet = typeof globalThis['CSSStyleSheet'] & {
replaceSync(cssText: string): void;
replace(cssText: string): void;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script type="module" src="./my-element.js"></script>
<style>
.styled my-element::part(paragraph) {
color: yellow;
border-color: white;
padding: 8px;
margin: 2px;
}

.styled {
background-color: black;
}

div {
padding: 4px;
}
</style>

<div class="styled">
<my-element></my-element>
</div>
<div>
<my-element></my-element>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { html, LitElement, css } from 'lit';
import { customElement } from 'lit/decorators.js';

@customElement('my-element')
export class MyElement extends LitElement {
static styles = css`
p {
color: blue;
border: 1px solid black;
padding: 4px;
margin-block: 4px;
}
`;

render() {
return html`<p part="paragraph">This is in a shadow root!</p>`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "/samples/v3-base.json",
"files": {
"my-element.ts": {},
"index.html": {}
},
"previewHeight": "120px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./my-element.js"></script>

<my-element array='1,"2",3,4,"5"'></my-element>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { html, LitElement } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';import {ComplexAttributeConverter} from 'lit';

/**
* Bidirectionally converts an array from an attribute to a property of the
* following format:
*
* array-attribute='1, "2", 3' to [1, '2', 3]
*/
export const arrayConverter: ComplexAttributeConverter<Array<unknown>> = {
toAttribute: (array: Array<unknown>) => {
return JSON.stringify(array).substring(1, JSON.stringify(array).length - 1);
},
fromAttribute: (value: string) => {
try {
return JSON.parse(`[${value}]`);
} catch {
return [];
}
}
};

@customElement('my-element')
export class MyElement extends LitElement {
@property({ converter: arrayConverter, reflect: true })
array: Array<number|string> = [];

render() {
return this.array.map((item) =>
html`<div>${typeof item}: ${item}</div>`
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "/samples/v3-base.json",
"files": {
"my-element.ts": {},
"index.html": {}
},
"previewHeight": "200px"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';

export type ScoreEvent = CustomEvent<number>;

@customElement('game-player')
export class GamePlayer extends LitElement {
render() {
return html`
<button @click=${() => this.handleScore(7)}>Touchdown!</button>
<button @click=${() => this.handleScore(3)}>Field goal!</button>
`;
}

handleScore(points: number) {
this.dispatchEvent(new CustomEvent('score', { detail: points, bubbles: true }));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script type="module" src="./score-board.js"></script>

<score-board></score-board>
Loading
Loading