Lit ships a full set of decorators beyond just @property and @customElement. This lesson catalogs every commonly used one and what it does.
The Full Decorator Toolkit
Beyond the core @customElement, @property, and @state decorators covered earlier, Lit provides several more specialized decorators for querying the rendered DOM, configuring event listener options, and other common needs — each one a thin, type-safe wrapper over functionality you could otherwise write by hand.
All decorators are imported from lit/decorators.js (or, for tree-shaking, their own specific sub-paths like lit/decorators/query.js), and require the same experimentalDecorators TypeScript configuration covered in the previous lesson.
@query/@queryAll give typed, cached access to specific elements in the rendered Shadow DOM, avoiding repeated manual querySelector calls.
Decorator Import Paths
import { customElement, property, state } from 'lit/decorators.js';
import { query, queryAll, queryAsync, queryAssignedElements } from 'lit/decorators.js';
import { eventOptions } from 'lit/decorators.js';
@query(selector) returns the first matching element within the component's Shadow DOM, typed as you annotate it.
@queryAll(selector) returns a static NodeList of every matching element.
@queryAsync(selector) returns a Promise resolving to the element once the component's next update completes — useful if the element might not exist yet.
@queryAssignedElements() returns the elements currently projected into a given <slot>, a decorator-based shortcut over manual assignedElements() calls.
Complete Lit Decorator Reference
Every commonly used Lit decorator and its purpose.
Decorator
Purpose
@customElement('tag-name')
Registers the class as a custom element
@property(options?)
Declares a public, attribute-backed reactive property
@state()
Declares an internal, non-attribute reactive property
@query(selector)
Cached reference to the first matching element in Shadow DOM
@queryAll(selector)
Cached NodeList of all matching elements
@queryAsync(selector)
Promise-based element lookup, resolves after next update
@queryAssignedElements(options?)
Elements currently projected into a slot
@eventOptions(options)
Applies addEventListener options to a class-method event handler
@query() in Depth
@query() caches the result after the first successful lookup by default, which is a meaningful optimization for elements that don't change identity across renders, but means the cached reference can become stale if the underlying DOM structure changes significantly. Pass true as the second argument to force a fresh lookup on every access instead.
@query('input') input!: HTMLInputElement; // cached after first successful lookup
@query('input', true) freshInput!: HTMLInputElement; // always re-queries
@eventOptions() for Class-Method Handlers
When an event handler is defined as a full class method (rather than an arrow-function field) and bound in the template with @event=${this.methodName}, @eventOptions() lets you attach addEventListener options like capture or passive directly to that method as a decorator, instead of using the inline options-object binding syntax from the event options lesson.
Manually writing repeated this.shadowRoot.querySelector(...) calls throughout a component instead of using @query().
Not realizing @query() caches its result by default, and being confused when a completely restructured DOM returns a stale reference.
Using @queryAsync() when the element is actually always present after the first render — @query() is simpler and sufficient in that case.
Forgetting the non-null assertion (!) or proper optional typing on @query()-decorated fields in strict TypeScript, since the element may not exist before the first render.
Key Takeaways
Lit provides decorators beyond the core three: @query, @queryAll, @queryAsync, @queryAssignedElements, and @eventOptions.
@query()/@queryAll() give typed, convenient access to elements within a component's own Shadow DOM.
@query() caches its result by default; pass true as a second argument to force fresh lookups.
@eventOptions() attaches addEventListener options to class-method-based event handlers.
Pro Tip
Reach for @query() the moment you write your second this.shadowRoot.querySelector(...) call in a component — it's a small change that immediately improves both readability and type safety over repeated manual queries.
You now have a complete decorator reference. Next, go deep on typed reactive properties specifically.