> ## Documentation Index
> Fetch the complete documentation index at: https://sprincul.sinfullycoded.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Share State Across Sprincul Models with the Global Store

> Use Sprincul.store to set, get, and subscribe to shared key/value state. Any model on the page can read and react to store changes without direct coupling.

The global store gives every model on your page access to the same key/value state without requiring you to wire models together manually. It is useful whenever two or more models need to react to the same piece of data — a selected theme, a logged-in user, a notification count — without one model knowing about the other's implementation.

## How it works

`Sprincul.store` is a flat key/value map backed by [nanostores](https://github.com/nanostores/nanostores) atoms. Any model (or any script on the page) can read from it, write to it, and subscribe to changes. You do not need to configure it; it is available as soon as you import `Sprincul`.

## API reference

### `Sprincul.store.set(key, value)`

Writes `value` under `key`. If the key does not exist yet, Sprincul creates the underlying atom automatically. All active subscribers for that key are notified.

```js theme={null}
Sprincul.store.set('theme', 'dark');
```

### `Sprincul.store.get(key)`

Returns the current value stored under `key`, or `undefined` if nothing has been set yet.

```js theme={null}
const theme = Sprincul.store.get('theme'); // 'dark' | undefined
```

### `Sprincul.store.subscribe(key, callback)`

Registers `callback` to run whenever the value at `key` changes. Returns an unsubscribe function you can call to stop listening.

```js theme={null}
const unsubscribe = Sprincul.store.subscribe('theme', (value) => {
  console.log('theme changed to:', value);
});

// Later, when you no longer need updates:
unsubscribe();
```

<Warning>
  `subscribe` fires **after** a value changes, not when you first call it. To read the current value at subscription time, call `Sprincul.store.get(key)` before subscribing.
</Warning>

### `Sprincul.store.clear()`

Removes all entries from the store. Existing subscribers are **not** automatically cleaned up, so call `unsubscribe()` on any active subscriptions before clearing if you want to avoid stale callbacks.

```js theme={null}
Sprincul.store.clear();
```

## When to seed store values

You can write to the store at any point — before registering models, before calling `Sprincul.init()`, or after. There is no required ordering. If you want a default value in place before any model reads or subscribes, set it early:

```js theme={null}
// Seed a default before init
Sprincul.store.set('theme', 'light');

Sprincul.register('ThemeSwitcher', ThemeSwitcher);
Sprincul.register('HeroSection', HeroSection);
Sprincul.init();
```

## Practical example: theme switcher and themed component

The following example shows two independent models communicating through the store. `ThemeSwitcher` writes the active theme, and `HeroSection` reads and reacts to it.

<CodeGroup>
  ```html HTML theme={null}
  <style>[data-cloaked] { display: none }</style>

  <div data-model="ThemeSwitcher">
    <button onclick="setLight">Light</button>
    <button onclick="setDark">Dark</button>
  </div>

  <section data-model="HeroSection" data-cloaked>
    <h1 data-bind-theme="applyTheme">Welcome</h1>
  </section>
  ```

  ```js ThemeSwitcher.js theme={null}
  import { SprinculModel, Sprincul } from 'sprincul';

  export default class ThemeSwitcher extends SprinculModel {
    setLight() {
      Sprincul.store.set('theme', 'light');
    }

    setDark() {
      Sprincul.store.set('theme', 'dark');
    }
  }
  ```

  ```js HeroSection.js theme={null}
  import { SprinculModel, Sprincul } from 'sprincul';

  export default class HeroSection extends SprinculModel {
    #unsubscribe = null;

    beforeInit() {
      // Seed state with whatever is already in the store (or a default)
      this.state.theme = Sprincul.store.get('theme') ?? 'light';
    }

    afterInit() {
      this.#unsubscribe = Sprincul.store.subscribe('theme', (value) => {
        this.state.theme = value ?? 'light';
      });
    }

    /** @param {HTMLElement} el */
    applyTheme(el) {
      el.dataset.theme = this.state.theme;
    }
  }
  ```

  ```js main.js theme={null}
  import { Sprincul } from 'sprincul';
  import ThemeSwitcher from './ThemeSwitcher.js';
  import HeroSection from './HeroSection.js';

  Sprincul.store.set('theme', 'light');

  Sprincul.registerAll({ ThemeSwitcher, HeroSection });
  Sprincul.init();
  ```
</CodeGroup>

<Tip>
  Reading the store in `beforeInit()` and subscribing in `afterInit()` is the recommended pattern. `beforeInit()` runs before bindings are attached, so any state you set there is ready when the first render pass fires.
</Tip>

## Avoiding memory leaks

Every call to `subscribe` returns an unsubscribe function. Hold onto it and call it when the model is torn down or when you no longer need the subscription. If you subscribe inside `afterInit()`, a good pattern is to store the unsubscribe function on the instance:

```js theme={null}
import { SprinculModel, Sprincul } from 'sprincul';

export default class Sidebar extends SprinculModel {
  #unsubscribeUser = null;

  afterInit() {
    this.#unsubscribeUser = Sprincul.store.subscribe('currentUser', (user) => {
      this.state.username = user?.name ?? 'Guest';
    });
  }

  // Call this when you remove the model from the DOM, or let Sprincul's
  // built-in cleanup handle it if the element is removed naturally.
  teardown() {
    this.#unsubscribeUser?.();
  }
}
```

Sprincul automatically destroys model instances when their root element is removed from the DOM, so subscriptions tied to that model's lifetime are cleaned up as part of normal page lifecycle management.
