Skip to content

Convert static styles/properties getter to class fields #495

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

Merged
merged 5 commits into from
Sep 13, 2021
Merged
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
Expand Up @@ -4,12 +4,10 @@ import {SuperElement} from './super-element.js';

@customElement('my-element')
export class MyElement extends SuperElement {
static get styles() {
return [
super.styles,
css`div {
color: red;
}`
];
}
static styles = [
super.styles,
css`div {
color: red;
}`
];
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import {Highlightable} from './highlightable.js'

@customElement('element-two')
export class ElementTwo extends Highlightable(LitElement) {
static get styles() {
return [
super.styles || [],
css`:host { display: block; }`
];
}
static styles = [
super.styles || [],
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
super.styles || [],
super.styles ?? [],

css`:host { display: block; }`
];
render(){
return this.renderHighlight(html`
<label>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import {html, css, LitElement} from 'lit';

export class SimpleGreeting extends LitElement {
static get styles() {
return css`p { color: blue }`;
}
static styles = css`p { color: blue }`;

static get properties() {
return {
name: {type: String}
}
}
static properties = {
name: {type: String}
};

constructor() {
super();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@ class MyElement extends LitElement {
@property({type: Boolean, reflect: true})
active: boolean = false;

static get styles() {
return css`
:host {
display: inline-block;
}
static styles = css`
:host {
display: inline-block;
}

:host([active]) {
border: 1px solid red;
}`;
}
:host([active]) {
border: 1px solid red;
}`;

render() {
return html`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@ type ToDoItem = {

@customElement('todo-list')
export class ToDoList extends LitElement {
static get styles() {
return css`
.completed {
text-decoration-line: line-through;
color: #777;
}
`;
}
static styles = css`
.completed {
text-decoration-line: line-through;
color: #777;
}
`;

@property()
listItems = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@ type ToDoItem = {

@customElement('todo-list')
export class ToDoList extends LitElement {
static get styles() {
return css`
.completed {
text-decoration-line: line-through;
color: #777;
}
`;
}
static styles = css`
.completed {
text-decoration-line: line-through;
color: #777;
}
`;

@property({attribute: false})
listItems = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@ type ToDoItem = {

@customElement('todo-list')
export class ToDoList extends LitElement {
static get styles() {
return css`
.completed {
text-decoration-line: line-through;
color: #777;
}
`;
}
static styles = css`
.completed {
text-decoration-line: line-through;
color: #777;
}
`;

@property({attribute: false})
listItems = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { LitElement, html } from 'lit-element';

class MyElement extends LitElement {
static get properties() {
return {
message: { type: String }
// TODO: Add a boolean property
// TODO: Add an array property
};
}
static properties = {
message: { type: String }
// TODO: Add a boolean property
// TODO: Add an array property
};
constructor() {
super();
this.message = 'Hello world! From my-element';
Expand Down
14 changes: 7 additions & 7 deletions packages/lit-dev-content/site/docs/components/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ Perform one time initialization tasks that must be done before the first [update
```js
constructor() {
super();
this.foo = foo;
this.bar = bar;
this.foo = 'foo';
this.bar = 'bar';
}
```
### connectedCallback() {#connectedcallback}
Expand All @@ -55,7 +55,7 @@ In `connectedCallback()` you should setup tasks that should only occur when the
```js
connectedCallback() {
super.connectedCallback()
addEventListener(keydown, this._handleKeydown);
addEventListener('keydown', this._handleKeydown);
}
```
### disconnectedCallback() {#disconnectedcallback}
Expand All @@ -73,7 +73,7 @@ This callback is the main signal to the element that it may no longer be used; a
```js
disconnectedCallback() {
super.disconnectedCallback()
window.removeEventListener(keydown, this._handleKeydown);
window.removeEventListener('keydown', this._handleKeydown);
}
```

Expand Down Expand Up @@ -174,7 +174,7 @@ The list of properties that have changed is stored in a Map that’s passed to a
Optionally, you can pass a property name and a previous value when calling `requestUpdate()`, which will be stored in the `changedProperties` map. This can be useful if you implement a custom getter and setter for a property. See [Reactive properties](/docs/components/properties/) for more information about implementing custom getters and setters.

```js
this.requestUpdate(state, this._previousState);
this.requestUpdate('state', this._previousState);
```

### Performing an update {#reactive-update-cycle-performing}
Expand Down Expand Up @@ -221,7 +221,7 @@ Implement `willUpdate()` to compute property values that depend on other propert
```js
willUpdate(changedProperties) {
// only need to check changed properties for an expensive computation.
if (changedProperties.has(firstName) || changedProperties.has(lastName)) {
if (changedProperties.has('firstName') || changedProperties.has('lastName')) {
this.sha = computeSHA(`${this.firstName} ${this.lastName}`);
}
}
Expand Down Expand Up @@ -322,7 +322,7 @@ async _loginClickHandler() {
this.loggedIn = true;
// Wait for `loggedIn` state to be rendered to the DOM
await this.updateComplete;
this.dispatchEvent(new Event(login));
this.dispatchEvent(new Event('login'));
}
```

Expand Down
30 changes: 13 additions & 17 deletions packages/lit-dev-content/site/docs/components/properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,16 @@ The argument to the `@property` decorators is an [options object](#property-opt

</div>

### Declaring properties in a static properties field
### Declaring properties in a static properties class field

To declare properties in a static `properties` field:
To declare properties in a static `properties` class field:

```js
class MyElement extends LitElement {
static get properties() {
return {
mode: {type: String},
data: {attribute: false},
};
}
static properties = {
mode: {type: String},
data: {attribute: false},
};

constructor() {
super();
Expand Down Expand Up @@ -215,14 +213,12 @@ Use the `@state` decorator to declare internal reactive state:
protected _active = false;
```

Using the static `properties` getter, you can declare internal reactive state by using the `state: true` option.
Using the static `properties` class field, you can declare internal reactive state by using the `state: true` option.

```js
static get properties() {
return {
_active: {state: true}
}
}
static properties = {
_active: {state: true}
};

constructor() {
this._active = false;
Expand Down Expand Up @@ -549,9 +545,9 @@ In rare cases, a subclass may need to change or add property options for a prope
To prevent Lit from generating a property accessor that overwrites the superclass's defined accessor, set `noAccessor` to `true` in the property declaration:

```js
static get properties() {
return { myProp: { type: Number, noAccessor: true } };
}
static properties = {
myProp: { type: Number, noAccessor: true }
};
```

You don't need to set `noAccessor` when defining your own accessors.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ See [Element.attachShadow()](https://developer.mozilla.org/en-US/docs/Web/API/El

### Implementing `createRenderRoot`

The default implementation of `createRenderRoot` creates an open shadow root and adds to it any styles set in the `static styles` property. For more information on styling see [Styles](/docs/components/styles/).
The default implementation of `createRenderRoot` creates an open shadow root and adds to it any styles set in the `static styles` class field. For more information on styling see [Styles](/docs/components/styles/).

To customize a component's render root, implement `createRenderRoot` and return the node you want the template to render into.

Expand Down
36 changes: 17 additions & 19 deletions packages/lit-dev-content/site/docs/components/styles.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ Shadow DOM provides strong encapsulation for styling. If Lit did not use Shadow

## Adding styles to your component {#add-styles}

You define scoped styles in the static `styles` property using the tagged template literal `css` function. Defining styles this way results in the most optimal performance:
You define scoped styles in the static `styles` class field using the tagged template literal `css` function. Defining styles this way results in the most optimal performance:

{% playground-example "docs/components/style/basic" "my-element.ts" %}

The styles you add to your component are _scoped_ using shadow DOM. For a quick overview, see [Shadow DOM](#shadow-dom).

The value of the static `styles` property can be:
The value of the static `styles` class field can be:

* A single tagged template literal.

Expand All @@ -32,7 +32,7 @@ The value of the static `styles` property can be:
static styles = [ css`...`, css`...`];
```

The static `styles` property is _almost always_ the best way to add styles to your component, but there are some use cases you can't handle this way—for example, customizing styles per instance. For alternate ways to add styles, see [Defining scoped styles in the template](#styles-in-the-template).
The static `styles` class field is _almost always_ the best way to add styles to your component, but there are some use cases you can't handle this way—for example, customizing styles per instance. For alternate ways to add styles, see [Defining scoped styles in the template](#styles-in-the-template).

### Using expressions in static styles {#expressions}

Expand All @@ -43,25 +43,23 @@ For tree-based or per-instance style customization, use CSS custom properties to
To prevent Lit components from evaluating potentially malicious code, the `css` tag only allows nested expressions that are themselves `css` tagged strings or numbers.

```js
static get styles() {
const mainColor = css`red`;
return css`
div { color: ${mainColor} }
`;
}
const mainColor = css`red`;
...
static styles = css`
div { color: ${mainColor} }
`;
```

This restriction exists to protect applications from security vulnerabilities whereby malicious styles, or even malicious code, can be injected from untrusted sources such as URL parameters or database values.

If you must use an expression in a `css` literal that is not itself a `css` literal, **and** you are confident that the expression is from a fully trusted source such as a constant defined in your own code, then you can wrap the expression with the `unsafeCSS` function:

```js
static get styles() {
const mainColor = 'red';
return css`
div { color: ${unsafeCSS(mainColor)} }
`;
}
const mainColor = 'red';
...
static styles = css`
div { color: ${unsafeCSS(mainColor)} }
`;
```

<div class="alert alert-info">
Expand Down Expand Up @@ -91,7 +89,7 @@ export const buttonStyles = css`
}`;
```

Your element can then import the styles and add them to its static `styles` property:
Your element can then import the styles and add them to its static `styles` class field:

```js
import { buttonStyles } from './button-styles.js';
Expand Down Expand Up @@ -185,7 +183,7 @@ my-element > div {

## Defining scoped styles in the template {#styles-in-the-template}

We recommend using the [static `styles` property](#add-styles) for optimal performance. However, sometimes you may want to define styles in the Lit template. There are two ways to add scoped styles in the template:
We recommend using the [static `styles` class field](#add-styles) for optimal performance. However, sometimes you may want to define styles in the Lit template. There are two ways to add scoped styles in the template:

* Add styles using a [`<style>` element](#style-element).
* Add styles using an [external style sheet](#external-stylesheet) (not recommended).
Expand All @@ -194,7 +192,7 @@ Each of these techniques has its own set of advantages and drawbacks.

### In a style element {#style-element}

Typically, styles are placed in the [static `styles` property](#add-styles); however, the element's static `styles` are evaluated **once per class**. Sometimes, you might need to customize styles **per instance**. For this, we recommend using CSS properties to create [themable elements](#theming). Alternatively, you can also include `<style>` elements in a Lit template. These are updated per instance.
Typically, styles are placed in the [static `styles` class field](#add-styles); however, the element's static `styles` are evaluated **once per class**. Sometimes, you might need to customize styles **per instance**. For this, we recommend using CSS properties to create [themable elements](#theming). Alternatively, you can also include `<style>` elements in a Lit template. These are updated per instance.

```js
render() {
Expand Down Expand Up @@ -251,7 +249,7 @@ To mitigate this cost, separate styles that require per-instance evaluation from

### Import an external stylesheet (not recommended) {#external-stylesheet}

While you can include an external style sheet in your template with a `<link>`, we do not recommend this approach. Instead, styles should be placed in the [static `styles` property](#add-styles).
While you can include an external style sheet in your template with a `<link>`, we do not recommend this approach. Instead, styles should be placed in the [static `styles` class field](#add-styles).

<div class="alert alert-info">

Expand Down
Loading