Skip to main content

Overview

ReactiveElement is the low-level base class that powers LitElement. It extends HTMLElement and implements the reactive update lifecycle, property/attribute management, and controller integration. Use this package when you want to build your own component base class without lit-html templating.
import {ReactiveElement} from '@lit/reactive-element';
Package: @lit/reactive-element
Extends: HTMLElement
Implements: ReactiveControllerHost

Static members

observedAttributes

static get observedAttributes(): string[]
Returns the list of attribute names that correspond to registered reactive properties. Automatically derived from the properties declaration. Calling this getter also triggers finalize() if it has not already run.

properties

static properties: PropertyDeclarations
A map of property names to PropertyDeclaration options. Declaring a property here creates a reactive accessor that requests an update whenever the property is set.
class MyElement extends ReactiveElement {
  static properties = {
    name: {type: String},
    count: {type: Number, reflect: true},
    active: {type: Boolean, state: true},
  };
}

styles

static styles?: CSSResultGroup
Styles to apply to the element’s shadow root. Accepts a CSSResult (from the css tag), a CSSStyleSheet, or an array of either.
static styles = [
  css`:host { display: block; }`,
  css`p { margin: 0; }`,
];

elementStyles

static elementStyles: Array<CSSResultOrNative>
The resolved, deduplicated list of styles computed from styles. Created lazily during finalize(). Override finalizeStyles() to customize how styles are processed.

shadowRootOptions

static shadowRootOptions: ShadowRootInit
Options passed to attachShadow() when creating the element’s shadow root. Defaults to {mode: 'open'}.
class MyElement extends ReactiveElement {
  static shadowRootOptions = {mode: 'closed' as const};
}

addInitializer()

static addInitializer(initializer: Initializer): void
Registers a function to run during each instance’s construction. Useful for decorators and other class-level integrations that need per-instance setup, such as attaching a ReactiveController.
initializer
(element: ReactiveElement) => void
required
A function called with the newly constructed element instance.
const myDecorator = (target: typeof ReactiveElement) => {
  target.addInitializer((instance) => {
    new MyController(instance);
  });
};
Initializers are stored per constructor. Subclass initializers run after superclass initializers.

finalize()

protected static finalize(): void
Completes class setup: processes the properties block, reads decorator metadata, builds the attribute-to-property map, and resolves elementStyles. Called automatically via observedAttributes. You should not need to call this directly.

Instance properties

updateComplete

get updateComplete(): Promise<boolean>
Resolves when the element has finished updating. The resolved value is true if the update completed without triggering another update, or false if a property was set inside updated(). The promise rejects if an exception is thrown during the update. To await additional async work after an update, override getUpdateComplete().
await this.updateComplete;
// DOM is now fully updated

hasUpdated

hasUpdated: boolean
true after the element’s first update completes. You can rely on renderRoot existing once hasUpdated is true.

isUpdatePending

isUpdatePending: boolean
true when an update has been requested but has not yet completed. Read-only in practice.

Instance methods

requestUpdate()

requestUpdate(
  name?: PropertyKey,
  oldValue?: unknown,
  options?: PropertyDeclaration
): void
Requests an asynchronous element update. Call with no arguments to trigger an update outside of a property change. When called from a manual property setter, pass the property name and old value so that the hasChanged option and changedProperties map are handled correctly.
name
PropertyKey
The name of the property that changed.
oldValue
unknown
The previous value of the property.
options
PropertyDeclaration
Property declaration options to use instead of the class-level options.

performUpdate()

protected performUpdate(): void
Executes a pending update synchronously. Calls shouldUpdate(), willUpdate(), update(), firstUpdated() (on first update), and updated(). Normally runs as a microtask; call directly only when you need to flush an update immediately.

scheduleUpdate()

protected scheduleUpdate(): void | Promise<unknown>
Called to schedule the update. Override to change update timing — for example, to defer updates until the next animation frame. If you return a Promise, the update awaits it before proceeding. Must call super.scheduleUpdate().
protected override async scheduleUpdate(): Promise<unknown> {
  await new Promise((resolve) => requestAnimationFrame(resolve));
  return super.scheduleUpdate();
}

shouldUpdate()

protected shouldUpdate(changedProperties: PropertyValues): boolean
Controls whether update() runs. Returns true by default. Override to conditionally skip updates.
changedProperties
PropertyValues
Map of properties that changed, with their previous values.
returns
boolean
Return true to proceed with the update, false to abort.

willUpdate()

protected willUpdate(changedProperties: PropertyValues): void
Called before update(). Use this to compute derived values that are needed during the update. Does not have access to the updated DOM.
changedProperties
PropertyValues
Map of properties that changed, with their previous values.
protected willUpdate(changed: PropertyValues<this>) {
  if (changed.has('firstName') || changed.has('lastName')) {
    this.fullName = `${this.firstName} ${this.lastName}`;
  }
}

update()

protected update(changedProperties: PropertyValues): void
Applies property values to the DOM. The default implementation reflects properties to attributes. Override in subclasses (such as LitElement) to render templates. Setting properties inside update() does not trigger another update.
changedProperties
PropertyValues
Map of properties that changed, with their previous values.

firstUpdated()

protected firstUpdated(changedProperties: PropertyValues): void
Called after the element’s first update. Use this for one-time DOM setup, such as focusing an element or initializing a third-party library.
changedProperties
PropertyValues
Map of properties that changed, with their previous values.
protected firstUpdated() {
  this.renderRoot.querySelector('input')?.focus();
}

updated()

protected updated(changedProperties: PropertyValues): void
Called after every update. Use this to perform tasks that require the updated DOM. Setting properties here triggers another update after the current cycle completes.
changedProperties
PropertyValues
Map of properties that changed, with their previous values.

getUpdateComplete()

protected getUpdateComplete(): Promise<boolean>
The override point for the updateComplete promise. Override this instead of the getter to await additional async work after an update completes.
protected override async getUpdateComplete(): Promise<boolean> {
  const result = await super.getUpdateComplete();
  await this._childElement.updateComplete;
  return result;
}
returns
Promise<boolean>
Resolves to true if the update completed without scheduling a further update.

addController()

addController(controller: ReactiveController): void
Registers a ReactiveController with this element. The controller’s lifecycle callbacks are called in sync with the element’s lifecycle. If the element is already connected, hostConnected() is called immediately.
controller
ReactiveController
required
The controller instance to register.

removeController()

removeController(controller: ReactiveController): void
Removes a previously registered ReactiveController from this element.
controller
ReactiveController
required
The controller instance to remove.

Types

PropertyDeclaration

Options that configure how a reactive property behaves.
interface PropertyDeclaration<Type = unknown, TypeHint = unknown> {
  readonly state?: boolean;
  readonly attribute?: boolean | string;
  readonly type?: TypeHint;
  readonly converter?: AttributeConverter<Type, TypeHint>;
  readonly reflect?: boolean;
  readonly noAccessor?: boolean;
  useDefault?: boolean;
  hasChanged?(value: Type, oldValue: Type): boolean;
}
state
boolean
When true, the property is internal state. It is not observed as an attribute and should not be set by users.
attribute
boolean | string
The attribute name to observe. false disables attribute observation. Defaults to the lowercased property name.
type
TypeHint
A type hint passed to the converter to help deserialize the attribute value. Supports String, Number, Boolean, Object, and Array.
converter
AttributeConverter
A function or object with fromAttribute and toAttribute methods. Converts between attribute strings and property values.
reflect
boolean
When true, the property value is reflected back to the corresponding attribute after each update.
noAccessor
boolean
When true, no reactive accessor is created. You must call requestUpdate() manually when the property changes.
useDefault
boolean
When true, treats the initial property value as a default. The initial value does not reflect to an attribute. When the attribute is removed, the property reverts to this default.
hasChanged
(value, oldValue) => boolean
Custom change detection function. Return true to request an update. Defaults to a strict identity check (!Object.is(value, oldValue)).

PropertyDeclarations

interface PropertyDeclarations {
  readonly [key: string]: PropertyDeclaration;
}
A map of property names to their PropertyDeclaration options. Assigned to static properties.

PropertyValues

type PropertyValues<T = any> = T extends object
  ? PropertyValueMap<T>
  : Map<PropertyKey, unknown>;
A map of property keys to their previous values, passed to lifecycle methods. Use PropertyValues<this> in subclass overrides for stronger typing.
protected updated(changed: PropertyValues<this>) {
  if (changed.has('src')) {
    this._loadImage(this.src);
  }
}

AttributeConverter

type AttributeConverter<Type = unknown, TypeHint = unknown> =
  | ComplexAttributeConverter<Type>
  | ((value: string | null, type?: TypeHint) => Type);

interface ComplexAttributeConverter<Type = unknown, TypeHint = unknown> {
  fromAttribute?(value: string | null, type?: TypeHint): Type;
  toAttribute?(value: Type, type?: TypeHint): unknown;
}
Converts between attribute strings and property values. A function form handles only fromAttribute. The object form supports both directions, which is required when using reflect: true.
const dateConverter: AttributeConverter<Date | null> = {
  fromAttribute: (value) => value ? new Date(value) : null,
  toAttribute: (value) => value?.toISOString() ?? null,
};

ReactiveController

Interface for composable lifecycle integrations.

Reactive properties

How property declarations work in practice.

Lifecycle

Full update lifecycle sequence.

LitElement

The full-featured component base class built on ReactiveElement.

Build docs developers (and LLMs) love