
Enter a search term above to see results...
Enter a search term above to see results...
Component state represents the dynamic, internal data managed within a component, often changing in response to user interaction or other events.
Unlike settings, which act as the external configuration API, state is private to the component instance.
Semantic UI uses its Signals-based reactivity system to manage state.
For a deeper understanding of reactivity concepts, see the Reactivity Guide.
Default state values are provided via the defaultState
object when creating a component using defineComponent
.
When a component instance is initialized, each property in the defaultState
object is automatically converted into a reactive Signal, allowing its value to be tracked and updated.
const defaultState = { selectedItem: null, items: []};
defineComponent({ tagName: 'my-component', defaultState});
The state
object is passed as an argument to lifecycle callbacks (like createComponent
, onRendered
, etc.) and handlers for events or key bindings. You can destructure state
to access individual state signals within these functions.
const createComponent = ({state}) => ({ incrementCounter() { // Modify state with .value - triggers re-renders state.counter.value += 1; },
getCount() { // Read state using .value return state.counter.value; // Or using .get() method // return state.counter.get(); }});
Flexible Syntax Both
.value
and.get()
can be used to read a signal’s current value within component logic. See Reactivity Basics for details. Note that accessing state within a Reaction establishes a dependency.
Within a component’s template, state signals can be accessed directly by their property name from the data context. You do not need to use .value
or .get()
here.
As an added convenience state values in templates can be accessed by name directly without using
.value
or.get()
{state.selectedItem} <!-- Wrong !-->{selectedItem.get} <!--- Wrong !-->{selectedItem} <!--- Right !-- >
For instance for the following state configuration
const defaultState = { isActive: false, items: []};
<p>Count: {counter}</p>
{#if isActive} <div class="active-content"> <p>Currently active!</p> </div>{else} <button class="activate">Activate</button>{/if}
{#each items} <li class="{#if selectedItem === id}selected{/if}"> {title} </li>{/each}
As mentioned, the state
object is available within declarative event handlers and key binding callbacks, allowing direct state manipulation in response to user input.
defineComponent({ // ...other component options events: { 'click .activate'({state}) { state.isActive.toggle(); } }});
defineComponent({ // ...other component options keys: { 'up'({state}) { state.x.decrement(10); } }});
Update a state signal’s value using its .set()
method, by assigning to its .value
property, or by using convenient built-in mutation helpers (like .increment()
, .toggle()
, .now()
, etc.) where available.
const onButtonClick = ({state}) => { state.counter.increment(1); state.lastClicked.value = new Date(); // equivalent state.lastClicked.set(new Date()); // equivalent state.lastClicked.now(); // helper equivalent};
Reactive updates are typically batched and flushed asynchronously. When multiple state changes need to occur together atomically, or you need to run code after the DOM has been updated based on state changes, you can use the afterFlush
callback available in lifecycle methods.
const createComponent = ({$, state, afterFlush}) => ({ resetForm() { // Make multiple state changes state.username.value = ''; state.email.value = ''; state.isSubmitted.value = false; state.errors.value = [];
// Run code after all updates are processed afterFlush(() => { console.log('Form reset complete'); // Focus the first field $('input[name="username"]').focus(); }); }});
State signals wrapping arrays or objects provide built-in mutation helpers (like .push()
, .removeIndex()
, .setProperty()
) that simplify common update operations while automatically handling reactivity.
See the Mutation Helpers guide and the Reactivity API Reference (specifically collection and array helpers) for more details.
const createComponent = ({state}) => ({ // Adding items to an array addItem() { // Using the built-in push method state.items.push({ id: generateId(), text: 'New Item' }); },
// Removing items by index removeIndex(index) { state.items.removeIndex(index); },
// Removing items by ID removeById(id) { state.items.removeItem(id); },
// Updating array items updateItem(index, newText) { // Update item at specific index state.items.setIndex(index, { ...state.items.getIndex(index), text: newText });
// Or update a property across all items state.items.setArrayProperty('isActive', false);
// Or update a property on a specific item state.items.setArrayProperty(2, 'isActive', true); },
// Object property updates updateProperty() { state.user.setProperty('name', 'Alex'); }});
These helper methods automatically handle reactivity updates and trigger re-renders as needed.
State management is often closely tied to the component lifecycle. Common patterns include:
createComponent
or onCreated
.onCreated
or onRendered
.reaction
) that respond to state changes within createComponent
or onCreated
.onDestroyed
.See the Reactive Computations guide for more information on creating reactive effects.
// Initialize state after component renderingconst onRendered = ({state, settings}) => { // Initialize state based on settings state.items.value = settings.initialItems || [];
// Start with first item selected if available if (state.items.value.length > 0) { state.selectedItem.value = state.items.value[0].id; }};
// Clean up state before component is removedconst onDestroyed = ({state}) => { // Clear any timers, subscriptions, etc. if (state.updateTimer.value) { clearInterval(state.updateTimer.value); }};