| name | umbraco-state-management |
| description | Understand and use state management in Umbraco backoffice (foundational concept) |
| version | 1.0.0 |
| location | managed |
| allowed-tools | Read, Write, Edit, WebFetch |
Umbraco State Management
What is it?
States in Umbraco are containers for reactive values that enable communication across component instances using the Observable pattern. An Umbraco State is a container for a value that you can create Observables from, which allows multiple observers to subscribe and automatically receive updates when the state changes. This pattern is particularly useful for sharing data between contexts and elements without tight coupling.
Documentation
Always fetch the latest docs before implementing:
Workflow
- Fetch docs - Use WebFetch on the URLs above
- Ask questions - What type of state? Who observes? Where to provide observable?
- Generate code - Implement state with observables based on latest docs
- Explain - Show what was created and how observation works
Minimal Examples
Basic State Usage
import { UmbStringState } from '@umbraco-cms/backoffice/observable-api';
const myState = new UmbStringState('initial value');
const myObservable = myState.asObservable();
this.observe(myObservable, (value) => {
console.log('Current value:', value);
});
myState.setValue('updated value');
State in Context Pattern
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbNumberState } from '@umbraco-cms/backoffice/observable-api';
export class MyContext extends UmbContextBase<MyContext> {
#counter = new UmbNumberState(0);
readonly counter = this.#counter.asObservable();
increment() {
this.#counter.setValue(this.#counter.getValue() + 1);
}
decrement() {
this.#counter.setValue(this.#counter.getValue() - 1);
}
}
Element Observing Context State
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { MY_CONTEXT } from './my-context.js';
export class MyElement extends UmbLitElement {
@state()
private _count = 0;
constructor() {
super();
this.consumeContext(MY_CONTEXT, (context) => {
this.observe(
context.counter,
(count) => {
this._count = count;
},
'_countObserver'
);
});
}
render() {
return html`
<div>Count: ${this._count}</div>
`;
}
}
Different State Types
import {
UmbStringState,
UmbNumberState,
UmbBooleanState,
UmbArrayState,
UmbObjectState
} from '@umbraco-cms/backoffice/observable-api';
const name = new UmbStringState('John');
const age = new UmbNumberState(25);
const isActive = new UmbBooleanState(true);
const items = new UmbArrayState(['item1', 'item2']);
const user = new UmbObjectState({ name: 'John', age: 25 });
Observable Parts (Derived State)
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
const itemsState = new UmbArrayState(['apple', 'banana', 'cherry']);
const firstItem = itemsState.asObservablePart(data => data?.[0]);
const itemCount = itemsState.asObservablePart(data => data.length);
this.observe(firstItem, (first) => {
console.log('First item:', first);
});
this.observe(itemCount, (count) => {
console.log('Total items:', count);
});
Array State Operations
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
const listState = new UmbArrayState<string>([]);
listState.setValue([...listState.getValue(), 'new item']);
listState.setValue(
listState.getValue().filter(item => item !== 'old item')
);
listState.setValue([]);
const current = listState.getValue();
Complete Context Example
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbStringState, UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
export class TodoContext extends UmbContextBase<TodoContext> {
#title = new UmbStringState('My Todo List');
#todos = new UmbArrayState<string>([]);
readonly title = this.#title.asObservable();
readonly todos = this.#todos.asObservable();
readonly todoCount = this.#todos.asObservablePart(data => data.length);
setTitle(value: string) {
this.#title.setValue(value);
}
addTodo(todo: string) {
this.#todos.setValue([...this.#todos.getValue(), todo]);
}
removeTodo(: ) {
.#todos.(
.#todos.().( t !== todo)
);
}
}
Key Concepts
State: Container for a value (private, mutable)
Observable: Subscription hook created from state (public, readonly)
Observer: Function that reacts to state changes via observe()
State Types:
UmbStringState - text values
UmbNumberState - numeric values
UmbBooleanState - boolean flags
UmbArrayState - collections
UmbObjectState - complex objects
UmbClassState - class instances
Observable Parts: Derived observables that only update when mapped value changes
Best Practice: Keep states private, expose observables publicly
Use Cases:
- Sharing data between context and elements
- Reactive UI updates
- Cross-component communication
- Derived/computed values
That's it! Always fetch fresh docs, keep examples minimal, generate complete working code.