From harness-claude
Implements Svelte stores pattern to share reactive state across component trees without prop-drilling, covering writable, readable, derived, and custom stores for Svelte 4/5 apps.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Share reactive state across any component tree using writable, readable, and derived stores with the Svelte store contract
Guides SvelteKit state scopes: runes for component-local, context API for subtrees, module singletons for globals. Fixes SSR data leaks and prop-drilling.
Guides Svelte and SvelteKit development for reactive components, stores, transitions, lifecycle hooks, SSR, file-based routing, and Vite deployment.
Guides Svelte 5 best practices for reactivity using $state, $derived, $effect, $props; covers event handling, styling, library integration. For writing/editing Svelte components.
Share bugs, ideas, or general feedback.
Share reactive state across any component tree using writable, readable, and derived stores with the Svelte store contract
writable — mutable shared state:
// stores/counter.ts
import { writable } from 'svelte/store';
export const count = writable(0);
// Helper methods (optional, common pattern)
export function increment() {
count.update((n) => n + 1);
}
export function reset() {
count.set(0);
}
$ auto-subscription prefix — no manual subscribe/unsubscribe needed:<script>
import { count, increment } from '$lib/stores/counter'
</script>
<p>Count: {$count}</p>
<button onclick={increment}>+</button>
<input bind:value={$myStore} />
readable — external data sources:
readable for stores driven by external events. The start function runs when the first subscriber attaches; the returned stop function runs when the last subscriber detaches:import { readable } from 'svelte/store';
export const time = readable(new Date(), (set) => {
const interval = setInterval(() => set(new Date()), 1000);
return () => clearInterval(interval);
});
derived — computed from other stores:
import { derived } from 'svelte/store';
import { count } from './counter';
export const doubled = derived(count, ($count) => $count * 2);
// Multiple sources:
export const summary = derived([firstName, lastName], ([$first, $last]) => `${$first} ${$last}`);
set when ready:export const userData = derived(
userId,
($id, set) => {
fetchUser($id).then(set);
return () => {}; // cleanup if needed
},
null
); // initial value while loading
Custom stores — encapsulated logic:
{ subscribe, set?, update? }) to create stores with domain-specific APIs:// stores/cart.ts
import { writable } from 'svelte/store';
function createCart() {
const { subscribe, update, set } = writable<CartItem[]>([]);
return {
subscribe,
addItem(item: CartItem) {
update((items) => [...items, item]);
},
removeItem(id: string) {
update((items) => items.filter((i) => i.id !== id));
},
clear() {
set([]);
},
};
}
export const cart = createCart();
Reading store values outside components:
get from svelte/store to read a store's value synchronously without subscribing:import { get } from 'svelte/store';
import { count } from './counter';
const current = get(count); // one-time read, no subscription
Store contract:
Any object with a subscribe method that follows Svelte's store contract is auto-subscribable with $. The contract:
subscribe(fn) — calls fn immediately with current value, then on every changeunsubscribe functionset and update methodsThis means you can make any reactive primitive a "store" — including RxJS Observables (with an adapter).
Svelte 4 vs. Svelte 5:
In Svelte 5, runes ($state, $derived) are the preferred reactivity model. Stores still work and are useful for cross-component shared state, but .svelte.ts files with rune-based reactive classes are the emerging pattern:
// Svelte 5 equivalent of a writable store
class Counter {
count = $state(0);
increment() {
this.count++;
}
}
export const counter = new Counter();
SSR and stores:
In SvelteKit SSR, module-level stores are shared between all requests on the server — this causes data leakage between users. Use the context API or load functions to pass per-request state instead of module-level stores for user-specific data.
When to use stores vs. context:
Debugging stores:
Subscribe in the browser console: import { cart } from './stores/cart'; cart.subscribe(console.log).
https://svelte.dev/docs/svelte/stores