[readonly] markdown buffer
State Managers for LWC: Be Excited, Keep Your Components Raw
LWC state managers are one of the most interesting changes in Summer '26. They move shared data, derived values and actions out of an overloaded parent component and into a dedicated state layer.
There is one important restraint: not every component should import the manager.
The three-layer pattern
1. State managers own page state
Use defineState(), atom(), computed() and setAtom() for values that coordinate several parts of a page: loaded records, filters, selected IDs, totals and shared actions.
import { defineState } from '@lwc/state';
export default defineState(({ atom, computed, setAtom }) => {
const rows = atom([]);
const severity = atom('All');
const selectedIds = atom([]);
const visibleRows = computed([rows, severity], () =>
rows.value.filter(
(row) => severity.value === 'All' || row.severity === severity.value
)
);
const setSeverity = (value) => setAtom(severity, value);
return { rows, selectedIds, visibleRows, setSeverity };
});
This removes coordination logic from the component tree without changing where durable Salesforce data belongs. LDS, UI API or Apex still provide the records.
2. The page shell and adaptors connect it
The page shell creates the state-manager instance. Descendant adaptor components retrieve the nearest instance with fromContext() and translate its state into ordinary properties and events.
import { LightningElement } from 'lwc';
import { fromContext } from '@lwc/state';
import alarmState from 'c/alarmState';
export default class AlarmListAdapter extends LightningElement {
state = fromContext(alarmState);
get rows() {
return this.state?.value.visibleRows ?? [];
}
handleSelection(event) {
this.state.value.toggleSelected(event.detail.alarmId);
}
}
Context keeps instances scoped. Two workspaces on one page can have independent state rather than sharing a global singleton.
3. Raw components stay raw
Rows, badges, lists and toolbars should normally accept @api properties and emit events. They should not know which state manager supplied the data.
import { LightningElement, api } from 'lwc';
export default class AlarmList extends LightningElement {
@api rows = [];
handleSelection(event) {
this.dispatchEvent(new CustomEvent('selection', {
detail: { alarmId: event.currentTarget.dataset.alarmId }
}));
}
}
That component remains easy to preview, test and reuse with another data source. If a severity pill imports the whole alarm workspace state merely to read one value, the state layer has leaked too far.
Where the boundary belongs
Salesforce also provides lightning/stateManager* modules for common record, layout, object-info and related-list data. They can reduce duplicated wires across a complex page, but the final presentation component can still remain independent.
When it earns its keep
Good uses include:
- a console with shared filters and selection
- a multi-step wizard
- a quote builder or cart
- coordinated dashboard panels
- a workspace where several components use the same record metadata
A single form field, a small card with one Apex call or a parent passing two values to one child does not need a state manager. Props and events remain the simpler answer.
State managers solve page-level coordination. The durable architecture is a stateful shell, thin adaptors and boring reusable UI. That gives LWC a stronger state model without replacing one tightly coupled component tree with another.