Skip to main content

Generating attributes for LitElement properties

· 3 min read

Streamline your code with a custom implementation of LitElement’s createProperty method.

Introduction to LitElement properties and attributes

A LitElement property is a JavaScript class property that is observed by LitElement. Whenever the value of a LitElement property changes, the update lifecycle will run to determine if the component needs to render.

An observed attribute is created for each LitElement property, and the attribute will have the same name as the property, in lowercase, if a name is not provided.

import { LitElement, property } from 'lit-element';

class MyComponent extends LitElement {
@property()
public propOne; // HTML attribute called "propone"

@property()
public propTwo; // HTML attribute called "proptwo"
}

You will often find yourself defining multi-word properties such as propOne above. This property is easy to read in camelCase but difficult to read as the lowercase attribute propone. For such properties, you can improve the readability of the attribute by naming it explicitly using a different convention, such as kebab-case.

import { LitElement, property } from 'lit-element';

class MyComponent extends LitElement {
@property({ attribute: 'prop-one' })
public propOne; // HTML attribute called "prop-one"

@property({ attribute: 'prop-two' })
public propTwo; // HTML attribute called "prop-two"
}

Overriding LitElement’s createProperty method

Explicitly naming attributes improves readability at the cost of maintainability. By specifying a name for the LitElement property and its attribute, you run the risk of renaming one without renaming the other.

import { LitElement, property } from 'lit-element';

class MyComponent extends LitElement {
@property({ attribute: 'prop-one' })
public butActuallyPropOne; // HTML attribute still called "prop-one"

@property({ attribute: 'prop-two' })
public butActuallyPropTwo; // HTML attribute still called "prop-two"
}

LitElement’s createProperty method can be overwritten to eliminate this risk and allow you to write less code (win-win!). The createProperty method is automatically called once for each property and is a great place to generate attribute names using any naming convention.

import { LitElement, property, PropertyDeclaration } from 'lit-element';
import { camelCaseToKebabCase } from 'some-library';

class MyComponent extends LitElement {
@property()
public butActuallyPropOne; // HTML attribute called "but-actually-prop-one"

@property()
public butActuallyPropTwo; // HTML attribute called "but-actually-prop-two"

static createProperty(name: PropertyKey, options: PropertyDeclaration) {
let customOptions = options;

// derive the attribute name if not already defined or disabled
if (
typeof options?.attribute === 'undefined' ||
options?.attribute === true
) {
customOptions = Object.assign({}, options, {
attribute: camelCaseToKebabCase(name.toString()),
});
}

// invoke the original method with the custom options to let LitElement do its thing
super.createProperty(name, customOptions);
}
}

Sharing the love

Overriding LitElement’s createProperty method is an easy way to simplify your code and make it less error-prone. But what if you are building multiple Web Components with LitElement? In this case, you can override the createProperty method within a base class or as a mixin so that your entire component library can benefit.