@lwc/errors
9.5.3 · 27 Oct 2026MIT384.1k / weekRepositoryHomepagenpmAtom feed
499 stable releases, newest first, by release line. Notes are quoted as the maintainers published them.
- 6.x
6.0.0
17 Jan 2024- breaking
Old behavior: the error is caught.
- breaking
New behavior: the error is uncaught.
- breaking
x-a
Note
These release notes are for the Lightning Web Components framework in open source only. If you use Lightning Base Components, Lightning Web Security, or other Salesforce products on the Lightning platform, see the Summer '24 release notes.
LWC v6.0.0 contains breaking changes. Please read carefully below if you are upgrading from v5.
If you are upgrading from v4, please upgrade to v5 first.
Note
LWC v6 corresponds to Salesforce release Summer '24 (API version 61).
Summary of new features
Form-Associated Custom Elements (FACE) and Element Internals are now supported.
Breaking changes
Native custom element lifecycle
Note
This change currently only applies to consumers of the LWC open-source project outside of the Salesforce Lightning platform.
Previous versions of LWC used a synthetic (polyfill) system to call the
connectedCallbackanddisconnectedCallbackcomponent lifecycle hooks. This was originally designed for legacy browsers such as Internet Explorer 11. Such browsers are no longer supported, and LWC v6 uses the native browser APIs instead.Important
Native vs synthetic custom element lifecycle is not the same as native vs synthetic shadow DOM. They are two entirely separate concepts.
This change may affect the firing of
connectedCallbackanddisconnectedCallbackhooks in your components, since the previous implementation did not perfectly align with the browser standard. Most commonly, this will occur in unit tests, or when manually creating components using thelwc.createElement()API. The new behavior also fixes common memory leaks caused bydisconnectedCallbacknot firing consistently.Native custom element lifecycle also unlocks support for Form-Associated Custom Elements (FACE) and Element Internals.
Changes you may see to
connectedCallbackanddisconnectedCallbackbehavior:New behavior when disconnected from the DOM
Note
This situation will probably only occur when writing tests that do not connect elements to the DOM.
LWC components now only fire
connectedCallbackwhen they are actually connected to the DOM. If they are disconnected from the DOM (i.e. they are not inside thedocument), thenconnectedCallbackwill not fire.For instance, if you are testing for an event to be fired from a
connectedCallback, this would previously work:export default class Foo extends LightningElement { connectedCallback() { this.dispatchEvent(new CustomEvent('foo', { bubbles: true, composed: true })) } }const element = createElement('x-foo', { is: Foo }) const div = document.createElement('div') div.addEventListener('foo', () => { console.log('received foo event!') }) div.appendChild(element) // triggers connectedCallbackIn the above example,
received foo event!would be logged to the console.After this change, the above no longer triggers the
connectedCallback, nor the event.Instead, you must ensure the element is connected to the DOM:
document.body.appendChild(div)
Once the element is in the DOM tree,
connectedCallbackwill fire as expected.New error behavior
Note
This situation will probably only occur if you are writing tests to capture errors thrown in
connectedCallback/disconnectedCallback. Most component authors should never have to deal with this.Errors thrown by
connectedCallbacks anddisconnectedCallbackare dispatched globally, rather than locally when elements are added/removed from the DOM.For example, let's say you have a component that throws an error in
connectedCallback:export default class Foo extends LightningElement { connectedCallback() { throw new Error('foo') } }And then you expect to be able to catch the error synchronously on
appendChild:const element = lwc.createElement('x-foo', { is: Foo }) try { document.body.appendChild(element) } catch (error) { console.log('caught error', error) }- breaking
Old behavior: the error is caught.
- breaking
New behavior: the error is uncaught.
The solution is to use a global
errorlistener:const listener = (error) => { console.log('Caught error', error) } try { window.addEventListener('error', listener) document.body.appendChild(element); } finally { window.removeEventListener('error', listener) }If you're using
@lwc/jest-*, then you can use the newtoThrowInConnectedCallbackAPI which will handle this logic for you.Note
Events dispatched in
connectedCallbackanddisconnectedCallbackare unaffected by this change.New timing behavior in native shadow DOM
The timing of
connectedCallbackhas changed slightly to align with native browser standards, when using native shadow DOM.For example, the timing of when
connectedCallbackfires in child components relative to parent components has changed. Consider this DOM tree:<x-a> #shadow-root | <x-a-child> </x-a> <x-b> #shadow-root | <x-b-child> </x-b> <x-c> #shadow-root | <x-c-child> </x-c>
Old behavior: the order of
connectedCallbacks firing is:- breaking
x-a - breaking
x-b - breaking
x-c - breaking
x-c-child - breaking
x-b-child - breaking
x-a-child
New behavior: the order of
connectedCallbacks firing is:- breaking
x-a - breaking
x-a-child - breaking
x-b - breaking
x-b-child - breaking
x-c - breaking
x-c-child
Note that, with the new behavior,
connectedCallbackfires in standard DOM depth-first tree-traversal order. (The old behavior was defined by the synthetic lifecycle polyfill, and did not follow the standard.)The relative timing of
renderedCallbackhas also changed due the new nativeconnectedCallbacktiming. For example, consider this DOM tree:<x-grandparent> <x-parent> <x-child></x-child> </x-parent> </x-grandparent>(Note that, in the above example, the
<x-parent>and<x-child>are slotted, not part of the shadow roots of their containers.)Old behavior: the order of lifecycle hooks firing is (example):
Component Lifecycle hook grandparent connectedCallback parent connectedCallback child connectedCallback child renderedCallback parent renderedCallback grandparent renderedCallback New behavior: the order of lifecycle hooks firing is (example):
Component Lifecycle hook grandparent connectedCallback grandparent renderedCallback parent connectedCallback parent renderedCallback child connectedCallback child renderedCallback Note that the above only applies to native shadow DOM. In synthetic shadow DOM, the ordering is the same, regardless of native vs synthetic custom element lifecycle (example). The same is true of light DOM (example).
In general, your components should not rely on the particular timing of
connectedCallbackorrenderedCallbackacross components. In case they do, please update to match the new timing behavior, or make your code agnostic to any particular timing.Note that the timing of
disconnectedCallbackhas not changed, except as noted elsewhere in these release notes.Shadow roots may be null after appending to disconnected elements
Consider this case:
<!-- app.html --> <template> <x-child></x-child> </template>
const elm = createElement("x-app", { is: App }) const div = document.createElement('div') div.appendChild(elm) console.log(elm.shadowRoot.querySelector('x-child'))Old behavior: logs the
<x-child>component, because thediv.appendChildtriggered the rendering of the child element.New behavior: logs
null, becausedivis disconnected from the DOM, preventing triggering of rendering.The resolution is to append the element to an element that is actually connected to the DOM. For example, in the above case:
document.body.appendChild(div);
New timing behavior during list rendering
Before LWC v6, certain scenarios with
for:eachwould not result inconnectedCallback/disconnectedCallbackfiring on components inside the iteration, even if the components were actually disconnected and re-connected to the DOM (for example, during list reordering).In LWC v6,
connectedCallback/disconnectedCallbackwill accurately fire to reflect that the underlying framework has removed and re-inserted elements into the DOM. This may be disruptive for components that do not correctly handle additionalconnectedCallback/disconnectedCallbackinvocations, or that have significant performance overhead for these callbacks.For example, if you have the iteration:
<template for:each={items} for:item="item"> <x-item key={item}></x-item> </template>... and if the
itemsarray is originally[1, 2, 3, 4]and later changes to[3, 4, 2, 1], then you would see the following callbacks being invoked after the list order changes:Old behavior: none of
connectedCallback,disconnectedCallback, norrenderedCallbackfire after reordering. (Demo)New behavior:
disconnectedCallbackfires and thenconnectedCallbackfires for list items 1 and 2 after reordering, because these items have been removed and re-inserted into the end of the list by the LWC framework. (Demo)This also affects
renderedCallback. Previously, you may have relied onrenderedCallbackfor your setup logic anddisconnectedCallbackfor your teardown logic. (For example: setting up event listeners or subscribing to a store.) Previously, this might work for some use cases. However, in LWC v6, your component may firedisconnectedCallbackand thenconnectedCallbackif it is inside of a list that is reordered – without firingrenderedCallback(if the data bindings inside the component did not change).For example, consider a list that is reordered from
[1, 2]to[2, 1]. In both cases, before reordering,connectedCallbackandrenderedCallbackare fired for items 1 and 2. However, after reordering, the following occurs:Old behavior: no lifecycle callbacks fire after reordering. (Demo)
New behavior:
disconnectedCallbackfires and thenconnectedCallbackfires for item 1. Additionally,renderedCallbackfires for item 1 but does not fire for its children. (Demo)A best practice is to do your setup logic in
connectedCallbackand teardown logic indisconnectedCallback. These two callbacks are perfect mirrors of each other – unlikerenderedCallback, which may fire multiple times if the component data changes, and may not fire during a simple list reordering.Fixed light DOM slot remapping
Note
On the Salesforce Lightning platform, this change only applies to components with an API version of 61 or above.
In previous versions of LWC, light DOM
<slot>s do not correctly remap with differentnames. This bug is fixed in LWC v6, but it may cause a breaking change if you rely on quirks of the previous behavior.The breaking changes are:
Slot attributes are no longer rendered
In LWC, light DOM slots are virtualized. This means that they do not rely on the native browser
<slot>elements orslotattributes at runtime, when the component is actually rendered to the DOM.Previously, your light DOM elements may have rendered with actual
slotattributes. As of LWC v6, theseslotattributes will not render. For example, consider this template:<template> <!-- this child is light DOM --> <x-child> <div slot="foo">hello</div> </x-child> </template>Previously this would render to the DOM as (demo):
<!-- Previous rendered content --> <div slot="foo">hello</div>
In LWC v6, this renders as (demo):
<!-- New rendered content --> <div>hello</div>
If you are relying on the presence of the
slotattribute (e.g. in a CSS selector or usingthis.querySelector()), then your code may break because theslotattribute is no longer present in the rendered DOM.For light DOM components, you are recommended to avoid CSS selectors or
this.querySelector()to match based on theslotattribute. Instead, you can uselwc:refor choose another CSS selector.For example, do not rely on CSS selectors like this:
// Don't do this const foo = this.querySelector('[slot="foo"]');Instead, use
lwc:ref:<x-child> <div slot="foo" lwc:ref="foo">hello</div> </x-child>const foo = this.refs.foo;
This may also change your Jest snapshots, which will need to be updated.
Strict light DOM slot forwarding
In previous versions of LWC, light DOM components that "wrap" a shadow DOM component were able to forward to the correct slot in the shadow DOM component without explicitly including a
slotattribute.For example, you may have a light DOM component like this:
<!-- x-slottable-light --> <template lwc:render-mode=light> <x-slottable-shadow> <slot name="foo"></slot> <slot></slot> </x-slottable-shadow> </template>In LWC v5, this would forward the
fooand default slots from<x-slottable-light>into<x-slottable-shadow>. However, this is actually a mistake, because proper slot forwarding should require aslotattribute on the<slot>element:<!-- x-slottable-light --> <template lwc:render-mode=light> <x-slottable-shadow> - <slot name="foo"></slot> + <slot name="foo" slot="foo"></slot> <slot></slot> </x-slottable-shadow> </template>In LWC v6, you must update your code to use the proper
slotattribute as shown above, or else the slotted content will not render correctly.- breaking
Demo in LWC v5 (working but should not work)
- breaking
Demo in LWC v6 (non-working)
- breaking
Demo in LWC v6 with corrected code (working)
Lifecycle callbacks accurately fire during list rendering
Before LWC v6, certain scenarios in list rendering would not result in
connectedCallback/disconnectedCallbackfiring on components inside the list, even if the components were actually disconnected and re-connected to the DOM (for example, during list reordering).In LWC v6,
connectedCallback/disconnectedCallbackwill accurately fire to reflect that the underlying framework has removed and re-inserted elements into the DOM. This may be disruptive for components that do not correctly handle additionalconnectedCallback/disconnectedCallbackinvocations, or that have significant performance overhead for these callbacks.For example, if you have the list:
<template for:each={items} for:item="item"> <x-item uid={item} key={item}></x-item> </template>... and if
itemsis originally[1, 2, 3, 4]and later changes to[3, 4, 2, 1]Demo of LWC v6 behavior compared to LWC v5 behavior.
Standard shadowrootmode attribute in SSR
Note
This change only applies to consumers using SSR (Server Side-Rendering), via the
renderComponent()API.In SSR, the attribute used to mark declarative shadow DOM roots has changed to match the latest browser standards. Instead of
shadowroot, the attribute is nowshadowrootmode.This may be a breaking change for you if you have a polyfill that is detecting the
shadowrootattribute rather thanshadowrootmode. It will also change your Jest snapshots, which will need to be updated.Old format:
<x-foo> <template shadowroot="open"> <div>Hello world</div> </template> </x-foo>New format:
<x-foo> - <template shadowroot="open"> + <template shadowrootmode="open"> <div>Hello world</div> </template> </x-foo>All changes
engine-dom: Use native lifecycle callbacks
engine-server: Use standard shadowrootmode attribute
- 5.x
5.3.0
10 Jan 2024template-compiler: Exclude comments from static parts when
lwc:preserve-commentsis disabled
What's Changed
template-compiler: Exclude comments from static parts when
lwc:preserve-commentsis disabled
5.2.2
3 Jan 2024Reading the note…
5.2.1
20 Dec 2023Reading the note…
5.2.0
12 Dec 2023Log shadow mode through engine reporting API
Add flag for forced shadow migrate mode
What's Changed
Log shadow mode through engine reporting API
Add flag for forced shadow migrate mode
5.1.0
17 Nov 2023Remove string.prototype.matchAll polyfill
What's Changed
Remove string.prototype.matchAll polyfill
5.0.10
20 Mar 2024Reading the note…
5.0.9
14 Feb 2024Reading the note…
5.0.8
8 Feb 2024Reading the note…
5.0.7
10 Jan 2024Reading the note…
5.0.6
10 Jan 2024Reading the note…
5.0.5
10 Jan 2024Reading the note…
5.0.4
9 Jan 2024Reading the note…
5.0.3
7 Dec 2023Reading the note…
5.0.2
14 Nov 2023Reading the note…
5.0.1
14 Nov 2023Reading the note…
5.0.0
8 Nov 2023- breaking
Use comment nodes for VFragment bookends
Adding missing aria attributes
rollup-plugin: Expose enableStaticContentOptimization, test it
LWC v5.0.0 contains breaking changes. Please read carefully below if you are upgrading from v4.
If you are upgrading from v3, please upgrade to v4 first.
Note
LWC v5 corresponds to Salesforce release Spring '24 (API version 60).
Breaking change
Empty comment nodes as VFragment bookends
Note
On the Salesforce Lightning platform, this change only applies to components with an API version of 60 or above.
Features like slots in light DOM, scoped slots and lwc:if use VFragment as virtual DOM nodes. The underlying implementation of VFragment used empty text nodes to aid the DOM diffing algorithm of
@lwc/engine-core. With this change, the empty text nodes are replaced with empty comment nodes.The impact of this change is expected to be minimal. Test snapshots may need to be updated, where new
<!---->comment nodes show up. Additionally, some usage of DOM node APIs may be impacted. If you usechildNode,nextSibling, etc in your code, there may be subtle changes in behavior.- breaking
Use comment nodes for VFragment bookends
Other changes
Adding missing aria attributes
rollup-plugin: Expose enableStaticContentOptimization, test it
- 4.x
4.0.1
25 Oct 2023Reading the note…
4.0.0
20 Oct 2023Reading the note…
- 3.x
3.8.0
17 Oct 2023Reading the note…
3.7.3
17 Oct 2023Reading the note…
3.7.2
16 Oct 2023Reading the note…
3.7.1
13 Oct 2023Reading the note…
3.7.0
11 Oct 2023Reading the note…
3.6.0
5 Oct 2023Reading the note…
3.5.0
29 Sep 2023Reading the note…
3.4.0
27 Sep 2023Reading the note…
3.3.3
22 Sep 2023Reading the note…
3.3.2
18 Sep 2023Reading the note…
3.3.1
18 Sep 2023Reading the note…
3.3.0
15 Sep 2023Reading the note…
3.2.0
24 Aug 2023Reading the note…
3.1.3
9 Aug 2023Reading the note…
3.1.2
3 Aug 2023Reading the note…
3.1.1
28 Jul 2023Reading the note…
3.1.0
21 Jul 2023Reading the note…
3.0.4
2 Oct 2023Reading the note…
3.0.3
27 Sep 2023Reading the note…
3.0.2
14 Jul 2023Reading the note…
3.0.1
7 Jul 2023Reading the note…
3.0.0
27 Jun 2023Reading the note…
- 2.x
2.50.0
19 Jun 2023Reading the note…
2.49.1
13 Jun 2023Reading the note…
2.49.0
13 Jun 2023Reading the note…
2.48.0
6 Jun 2023Reading the note…
2.47.0
5 Jun 2023Reading the note…
2.46.0
1 Jun 2023Reading the note…
2.45.5
23 May 2023Reading the note…
2.45.4
23 May 2023Reading the note…
2.45.3
19 May 2023Reading the note…