Lit manages your reactive properties and their corresponding attributes. In particular:
- Reactive updates. Lit generates a getter/setter pair for each reactive property. When a reactive property changes, the component schedules an update.
- Attribute handling. By default, Lit sets up an observed attribute corresponding to the property, and updates the property when the attribute changes. Property values can also, optionally, be reflected back to the attribute.
- Superclass properties. Lit automatically applies property options declared by a superclass. You don't need to redeclare properties unless you want to change options.
- Element upgrade. If a Lit component is defined after the element is already in the DOM, Lit handles upgrade logic, ensuring that any properties set on an element before it was upgraded trigger the correct reactive side effects when the element upgrades.
Public properties and internal statePermalink to “Public properties and internal state”
Public properties are part of the component's public API. In general, public properties—especially public reactive properties—should be treated as input.
The component shouldn't change its own public properties, except in response to user input. For example, a menu component might have a public
selected property that can be initialized to a given value by the owner of the element, but that is updated by the component itself when the user selects an item. In these instances, the component should dispatch an event to indicate to the component's owner that the
selected property changed. See Dispatching events for more details.
Lit also supports internal reactive state. Internal reactive state refers to reactive properties that aren't part of the component's API. These properties don't have a corresponding attribute, and are typically marked protected or private in TypeScript.
The component manipulates its own internal reactive state. In some cases, internal reactive state may be initialized from public properties—for example, if there is an expensive transformation between the user-visible property and the internal state.
As with public reactive properties, updating internal reactive state triggers an update cycle. For more information, see Internal reactive state.
Public reactive propertiesPermalink to “Public reactive properties”
Declare your element's public reactive properties using decorators or the static
In either case, you can pass an options object to configure features for the property.
Declaring properties with decoratorsPermalink to “Declaring properties with decorators”
@property decorator with a class field declaration to declare a reactive property.
The argument to the
@property decorators is an options object. Omitting the argument is equivalent to specifying the default value for all options.
Declaring properties in a static properties class fieldPermalink to “Declaring properties in a static properties class field”
To declare properties in a static
properties class field:
An empty option object is equivalent to specifying the default value for all options.
Avoiding issues with class fields when declaring propertiesPermalink to “Avoiding issues with class fields when declaring properties”
For TypeScript, you may use class fields for declaring reactive properties as long as you use one of these patterns:
- Set the
useDefineForClassFieldssetting in your
false. Note, this is not required for some configurations of TypeScript, but it's recommended to explicitly set it to
- Add the
declarekeyword on the field, and put the field's initializer in the constructor.
true in the
assumptions config of your
babelrc. Note, for older versions of Babel, you also need to include the plugin
For information about using class fields with decorators, see Avoiding issues with class fields and decorators.
Property optionsPermalink to “Property options”
The options object can have the following properties:
Whether the property is associated with an attribute, or a custom name for the associated attribute. Default: true. If
attributeis false, the
typeoptions are ignored. For more information, see Setting the attribute name.
A function called whenever the property is set to determine if the property has changed, and should trigger an update. If unspecified, LitElement uses a strict inequality check (
newValue !== oldValue) to determine whether the property value has changed. For more information, see Customizing change detection.
Set to true to avoid generating the default property accessors. This option is rarely necessary. Default: false. For more information, see Preventing Lit from generating a property accessor.
Whether property value is reflected back to the associated attribute. Default: false. For more information, see Enabling attribute reflection.
Set to true to declare the property as internal reactive state. Internal reactive state triggers updates like public reactive properties, but Lit doesn't generate an attribute for it, and users shouldn't access it from outside the component. Equivalent to using the
@statedecorator. Default: false. For more information, see Internal reactive state.
When converting a string-valued attribute into a property, Lit's default attribute converter will parse the string into the type given, and vice-versa when reflecting a property to an attribute. If
converteris set, this field is passed to the converter. If
typeis unspecified, the default converter treats it as
type: String. See Using the default converter.
When using TypeScript, this field should generally match the TypeScript type declared for the field. However, the
typeoption is used by the Lit's runtime for string serialization/deserialization, and should not be confused with a type-checking mechanism.
- The property's setter is called.
- The setter calls the component's
- The property's old and new values are compared.
- By default Lit uses a strict inequality test to determine if the value has changed (that is
newValue !== oldValue).
- If the property has a
hasChangedfunction, it's called with the property's old and new values.
- By default Lit uses a strict inequality test to determine if the value has changed (that is
- If the property change is detected, an update is scheduled asynchronously. If an update is already scheduled, only a single update is executed.
- The component's
updatemethod is called, reflecting changed properties to attributes and re-rendering the component's templates.
Immutable data pattern. Treat objects and arrays as immutable. For example, to remove an item from
myArray, construct a new array:
While this example is simple, it's often helpful to use a library like Immer to manage immutable data. This can help avoid tricky boilerplate code when setting deeply nested objects.
Manually triggering an update. Mutate the data and call
requestUpdate()to trigger an update directly. For example:
When called with no arguments,
requestUpdate()schedules an update, without calling a
hasChanged()function. But note that
requestUpdate()only causes the current component to update. That is, if a component uses the code shown above, and the component passes
this.myArrayto a subcomponent, the subcomponent will detect that the array reference hasn't changed, so it won't update.
To observe an attribute (set a property from an attribute), the attribute value must be converted from a string to match the property type.
To reflect an attribute (set an attribute from a property), the property value must be converted to a string.
Change the property name so it defaults to false. For example, the web platform uses the
disabledattribute (defaults to false), not
Use a string-valued or number-valued attribute instead.
Omitting the options object or specifying an empty options object is equivalent to specifying the default value for all options.
Internal reactive statePermalink to “Internal reactive state”
Internal reactive state refers to reactive properties that are not part of the component's public API. These state properties don't have corresponding attributes, and aren't intended to be used from outside the component. Internal reactive state should be set by the component itself.
@state decorator to declare internal reactive state:
Using the static
properties class field, you can declare internal reactive state by using the
state: true option.
Internal reactive state shouldn't be referenced from outside the component. In TypeScript, these properties should be marked as private or protected. We also recommend using a convention like a leading underscore (
Internal reactive state works just like public reactive properties, except that there is no attribute associated with the property. The only option you can specify for internal reactive state is the
@state decorator can also serve as a hint to a code minifier that the property name can be changed during minification.
What happens when properties changePermalink to “What happens when properties change”
A property change can trigger a reactive update cycle, which causes the component to re-render its template.
When a property changes, the following sequence occurs:
Note that if you mutate an object or array property, it won't trigger an update, because the object itself hasn't changed. For more information, see Mutating object and array properties.
There are many ways to hook into and modify the reactive update cycle. For more information, see Reactive update cycle.
For more information about property change detection, see Customizing change detection.
Mutating object and array propertiesPermalink to “Mutating object and array properties”
Mutating an object or array doesn't change the object reference, so it won't trigger an update. You can handle object and array properties in one of two ways:
In general, using top-down data flow with immutable objects is best for most applications. It ensures that every component that needs to render a new value does (and does so as efficiently as possible, since parts of the data tree that didn't change won't cause components that rely on them to update).
Mutating data directly and calling
requestUpdate() should be considered an advanced use case. In this case, you (or some other system) need to identify all the components that use the mutated data and call
requestUpdate() on each one. When those components are spread across an application, this gets hard to manage. Not doing so robustly means that you might modify an object that's rendered in two parts of your application, but only have one part update.
In simple cases, when you know that a given piece of data is only used in a single component, it should be safe to mutate the data and call
requestUpdate(), if you prefer.
AttributesPermalink to “Attributes”
By default, Lit sets up an observed attribute corresponding to each public reactive property, and updates the property when the attribute changes. Property values can also, optionally, be reflected (written back to the attribute).
Boolean properties that expose an attribute should default to false. For more information, see Boolean attributes.
Setting the attribute namePermalink to “Setting the attribute name”
By default, Lit creates a corresponding observed attribute for all public reactive properties. The name of the observed attribute is the property name, lowercased:
To create an observed attribute with a different name, set
attribute to a string:
To prevent an observed attribute from being created for a property, set
false. The property will not be initialized from attributes in markup, and attribute changes won't affect it.
Internal reactive state never has an associated attribute.
An observed attribute can be used to provide an initial value for a property from markup. For example:
Using the default converterPermalink to “Using the default converter”
Lit has a default converter that handles
Object property types.
To use the default converter, specify the
type option in your property declaration:
If you don't specify a type or a custom converter for a property, it behaves as if you'd specified
The tables below shows how the default converter handles conversion for each type.
From attribute to property
|If the element has the corresponding attribute, set the property to the attribute value.|
|If the element has the corresponding attribute, set the property to |
|If the element has the corresponding attribute, set the property to true.|
If not, set the property to false.
|If the element has the corresponding attribute, set the property value to |
For any case except
Boolean, if the element doesn't have the corresponding attribute, the property keeps its default value, or
undefined if no default is set.
From property to attribute
|If property is defined and non-null, set the attribute to the property value.|
If property is null or undefined, remove the attribute.
|If property is truthy, create the attribute and set its value to an empty string.|
If property is falsy, remove the attribute
|If property is defined and non-null, set the attribute to |
If property is null or undefined, remove the attribute.
Providing a custom converterPermalink to “Providing a custom converter”
You can specify a custom property converter in your property declaration with the
converter can be an object or a function. If it is an object, it can have keys for
converter is a function, it is used in place of
toAttribute function is supplied for a reflected attribute, the attribute is set to the property value using the default converter.
undefined, the attribute is removed.
Boolean attributesPermalink to “Boolean attributes”
For a boolean property to be configurable from an attribute, it must default to false. If it defaults to true, you cannot set it to false from markup, since the presence of the attribute, with or without a value, equates to true. This is the standard behavior for attributes in the web platform.
If this behavior doesn't fit your use case, there are a couple of options:
Enabling attribute reflectionPermalink to “Enabling attribute reflection”
You can configure a property so that whenever it changes, its value is reflected to its corresponding attribute. Reflected attributes are useful because attributes are visible to CSS, and to DOM APIs like
Attributes should generally be considered input to the element from its owner, rather than under control of the element itself, so reflecting properties to attributes should be done sparingly. It's necessary today for cases like styling and accessibility, but this is likely to change as the platform adds features like the
:state pseudo selector and the Accessibility Object Model, which fill these gaps.
Reflecting properties of type object or array is not recommended. This can cause large objects to serialize to the DOM which can result in poor performance.
Lit tracks reflection state during updates. You may have realized that if property changes are reflected to an attribute and attribute changes update the property, it has the potential to create an infinite loop. However, Lit tracks when properties and attributes are set specifically to prevent this from happening
Custom property accessorsPermalink to “Custom property accessors”
By default, LitElement generates a getter/setter pair for all reactive properties. The setter is invoked whenever you set the property:
Generated accessors automatically call
requestUpdate(), initiating an update if one has not already begun.
Creating custom property accessorsPermalink to “Creating custom property accessors”
To specify how getting and setting works for a property, you can define your own getter/setter pair. For example:
To use custom property accessors with the
@state decorators, put the decorator on the getter, as shown above.
The setters that Lit generates automatically call
requestUpdate(). If you write your own setter you must call
requestUpdate() manually, supplying the property name and its old value.
In most cases, you do not need to create custom property accessors. To compute values from existing properties, we recommend using the
willUpdate callback, which allows you to set values during the update cycle without triggering an additional update. To perform a custom action after the element updates, we recommend using the
updated callback. A custom setter can be used in rare cases when it's important to synchronously validate any value the user sets.
If your class defines its own accessors for a property, Lit will not overwrite them with generated accessors. If your class does not define accessors for a property, Lit will generate them, even if a superclass has defined the property or accessors.
Prevent Lit from generating a property accessorPermalink to “Prevent Lit from generating a property accessor”
In rare cases, a subclass may need to change or add property options for a property that exists on its superclass.
To prevent Lit from generating a property accessor that overwrites the superclass's defined accessor, set
true in the property declaration:
You don't need to set
noAccessor when defining your own accessors.
Customizing change detectionPermalink to “Customizing change detection”
All reactive properties have a function,
hasChanged(), which is called when the property is set.
hasChanged compares the property's old and new values, and evaluates whether or not the property has changed. If
hasChanged() returns true, Lit starts an element update if one is not already scheduled. For more information on updates, see Reactive update cycle .
The default implementation of
hasChanged() uses a strict inequality comparison:
newVal !== oldVal.
hasChanged() for a property, specify it as a property option:
In the following example,
hasChanged() only returns true for odd values.