On This Page
Signals
Signals are the core primitive for reactive state in Semantic UI. They hold a value and automatically track dependencies, notifying dependent computations—Reactions—when their value changes.
Creating Signals
To create a signal import Signal from the @semantic-ui/reactivity package then initialize it with a value.
import { Signal } from '@semantic-ui/reactivity';
// Create signals for different data typesconst counter = new Signal(0);const userName = new Signal('Alice');const isActive = new Signal(true);const items = new Signal(['apple', 'banana']);const userProfile = new Signal({ id: 1, name: 'Bob' });Triggering Reactivity
A Signal’s value can be accessed using .get() or .value.
console.log(counter.get()); // Output: 0console.log(userName.value); // Output: AliceIf this occurs within a reactive context (like a Reaction or a template expression) it will establish a reactive dependency and rerun the function whenever the value is updated.
reaction(() => { console.log(counter.get()); // outputs log whenever value changes});Controlling Reactivity There are many ways to control the reactivity of signals in your app. For instance to access a Signal’s value without creating a dependency use the
.peek()method. See Reactive Performance and Reactive Controls for more information.
Updating Signal Values
Update a Signal’s value using the .set() method or by directly assigning to the .value property. This will notify any dependent Reactions to re-run.
// Using .set()counter.set(1);console.log(counter.get()); // Output: 1
// Using .value assignmentuserName.value = 'Charlie';console.log(userName.value); // Output: CharlieSemantic UI also provides convenient mutation helpers directly on Signal instances for common update patterns, especially for arrays and objects.
// Using a mutation helpercounter.increment(); // Equivalent to counter.set(counter.peek() + 1)console.log(counter.get()); // Output: 2Signals and Foreign References
By default, Signals deep-freeze object and array values on set(). This catches the most common reactivity bug — mutating a value in place without notifying subscribers — by throwing a TypeError at the mutation site instead of silently dropping the update.
Deep-freezing has one important caveat: if the object you store is also held internally by a library, freezing it will break that library the next time it mutates its own reference.
When you need
{ safety: 'reference' }: if you’re storing an object in a signal that you did not construct yourself — anything returned from a library, fetched from an API, or passed through a callback — default tosafety: 'reference'. Freeze is the right default for state your own code owns end-to-end. For borrowed data,referenceavoids poisoning the lender’s internal references.
Worked Example: Search Index
Pagefind returns result objects and continues to use them internally — subsequent .data() calls on each result mutate pagefind’s own cached state. Storing the results under the default freeze mode freezes pagefind’s internal objects and later crashes its loader:
const defaultState = { // ❌ default freeze — pagefind's internal mutation of the stored objects will throw rawResults: [],};Opt this specific signal out of freeze:
const defaultState = { // ✓ signal holds third-party-owned data; don't freeze rawResults: { value: [], options: { safety: 'reference' } },};The rest of your component state keeps the default freeze protection — only the signal carrying borrowed data opts out.
Ad-hoc Construction
For signals created outside a defaultState declaration, pass the preset as the second argument:
const results = new Signal(pagefindData, { safety: 'reference' });Creating Derived Signals
Signals can be transformed and combined to create new reactive values:
const items = new Signal(['apple', 'banana', 'cherry']);
// Transform a single signal with derive()const itemCount = items.derive(arr => arr.length);
// Combine multiple signals with computed()const shoppingList = Signal.computed(() => `You have ${itemCount.get()} items: ${items.get().join(', ')}`);
console.log(shoppingList.get()); // "You have 3 items: apple, banana, cherry"Learn More For complete information about derived and computed signals, see the Dependent Signals guide.
Advanced Usage For more configuration options, such as customizing equality checks or value cloning behavior, see the Signal Options & Configuration guide.