npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

svelte-persisted-state

v1.2.0

Published

Svelte 5 persisted states, [svelte-persisted-store](https://github.com/joshnuss/svelte-persisted-store), but implemented with Svelte 5 Runes.

Readme

svelte-persisted-state

Svelte 5 persisted states, svelte-persisted-store, but implemented with Svelte 5 Runes.

Requirements

This package requires Svelte 5. It is not compatible with Svelte 4 or earlier versions.

Installation

npm install svelte-persisted-state

API

The persistedState function creates a persisted state that automatically syncs with local storage, session storage, or browser cookies.

Parameters

  • key: A string key used for storage.
  • initialValue: The initial value of the state.
  • options: An optional object with the following properties:
    • storage: 'local' (default), 'session', or 'cookie'
    • serializer: Custom serializer object with parse and stringify methods (default: JSON)
    • syncTabs: Boolean to sync state across tabs (default: true, only works with localStorage)
    • cookieOptions: Cookie-specific configuration object (only applies when storage is 'cookie'):
      • expireDays: Number of days before cookie expires (default: 365, max: 400 due to browser limits)
      • maxAge: Max-Age in seconds (takes precedence over expireDays if both are specified)
      • path: Cookie path (default: '/')
      • domain: Cookie domain (default: current domain)
      • secure: Secure flag - cookie only sent over HTTPS (default: false)
      • sameSite: SameSite attribute for CSRF protection - 'Strict' | 'Lax' | 'None' (default: 'Lax')
      • httpOnly: HttpOnly flag - prevents client-side script access (default: false)
    • onWriteError: Function to handle write errors
    • onParseError: Function to handle parse errors
    • beforeRead: Function to process value before reading
    • beforeWrite: Function to process value before writing

Return Value

The persistedState function returns an object with the following properties:

  • current: Get or set the current state value.
  • reset(): Reset the state to its initial value.

Usage

Basic Usage

import { persistedState } from 'svelte-persisted-state';

const myState = persistedState('myKey', 'initialValue');

// Use myState.current to get or set the state
console.log(myState.current);
myState.current = 'newValue';

// Reset to initial value
myState.reset();

Typed Usage

import { persistedState } from 'svelte-persisted-state';

interface UserPreferences {
	theme: 'light' | 'dark';
	fontSize: number;
	notifications: boolean;
}

const userPreferences = persistedState<UserPreferences>(
	'userPreferences',
	{
		theme: 'light',
		fontSize: 16,
		notifications: true
	},
	{
		storage: 'local',
		syncTabs: true,
		beforeWrite: (value) => {
			console.log('Saving preferences:', value);
			return value;
		},
		onWriteError: (error) => {
			console.error('Failed to save preferences:', error);
		}
	}
);

// Set a new value
function toggleTheme() {
	userPreferences.current = {
		...userPreferences.current,
		theme: userPreferences.current.theme === 'light' ? 'dark' : 'light'
	};
}

function toggleTheme() {
	userPreferences.current.theme = userPreferences.current.theme === 'light' ? 'dark' : 'light';
}

// Using $derived for reactive computations
const theme = $derived(userPreferences.current.theme);

// The UI will automatically update when the state changes

Cookie Storage

You can use cookies for storage, which is useful for server-side rendering scenarios or when you need data to persist across different subdomains:

import { persistedState } from 'svelte-persisted-state';

// Basic cookie usage (expires after 365 days by default)
const cookieState = persistedState('myCookieKey', 'defaultValue', {
	storage: 'cookie'
});

// Custom cookie expiration (expires after 30 days)
const shortTermCookie = persistedState(
	'tempData',
	{ userId: null },
	{
		storage: 'cookie',
		cookieExpireDays: 30
	}
);

// Long-term cookie (expires after 2 years, most browsers limit to 400 days)
const longTermPrefs = persistedState(
	'userPreferences',
	{ theme: 'light' },
	{
		storage: 'cookie',
		cookieExpireDays: 730
	}
);

Important Notes about Cookie Storage:

  • Cookies have a size limit (typically 4KB per cookie)
  • syncTabs option doesn't work with cookies (cookies don't trigger storage events)
  • Cookies are sent with every HTTP request to your domain
  • Cookie expiration can be customized with the cookieExpireDays option

Browser Limitations

Important: Modern browsers enforce a maximum cookie expiration limit:

  • Chrome (since August 2022) and other modern browsers cap cookie expiration at 400 days maximum
  • Cookies requesting longer expiration are automatically reduced to 400 days
  • This limit is part of the updated HTTP cookie specification (RFC 6265bis)

Storage Comparison

| Feature | localStorage | sessionStorage | cookies | | ------------------ | --------------------------- | ----------------------- | ------------------------ | | Persistence | Until manually cleared | Until tab/window closes | Until expiration date | | Size Limit | ~5-10MB | ~5-10MB | ~4KB | | Server Access | No | No | Yes (sent with requests) | | Tab Sync | Yes (with syncTabs: true) | No | No | | SSR Compatible | No | No | Yes | | Expiration | Manual | Automatic | Configurable |

Examples

Different Storage Types

// localStorage (default)
const localState = persistedState('local-key', 'value');

// sessionStorage
const sessionState = persistedState('session-key', 'value', {
	storage: 'session'
});

Cookie Configuration

// Authentication cookie with security options
const authToken = persistedState('auth-token', null, {
	storage: 'cookie',
	cookieOptions: {
		expireDays: 7, // Weekly re-authentication
		secure: true, // Only send over HTTPS
		sameSite: 'Strict', // Maximum CSRF protection
		path: '/' // Available site-wide
	}
});

// User preferences with balanced security
const userPreferences = persistedState('user-prefs', defaultPrefs, {
	storage: 'cookie',
	cookieOptions: {
		expireDays: 90, // Quarterly preference reset
		secure: true, // HTTPS only
		sameSite: 'Lax', // Balance security and usability
		path: '/' // Available site-wide
	}
});

// Shopping cart for specific site section
const shoppingCart = persistedState('cart', [], {
	storage: 'cookie',
	cookieOptions: {
		expireDays: 14, // Two-week shopping consideration
		path: '/shop', // Only available in shop section
		secure: true, // HTTPS only
		sameSite: 'Lax'
	}
});

// Cross-subdomain application state
const globalState = persistedState('global-user', userData, {
	storage: 'cookie',
	cookieOptions: {
		expireDays: 30,
		domain: '.example.com', // Available across all subdomains
		secure: true, // HTTPS only
		sameSite: 'None', // Required for cross-site cookies
		path: '/'
	}
});

// Using max-age
const maxAgeCookie = persistedState('session-data', sessionData, {
	storage: 'cookie',
	cookieOptions: {
		maxAge: 3600, // 1 hour in seconds
		secure: true,
		sameSite: 'Strict',
		path: '/'
	}
});

// Using expires (expireDays)
const expiresCookie = persistedState('data1', value, {
	storage: 'cookie',
	cookieOptions: {
		expireDays: 30
	}
});

Complete Example

<script lang="ts">
	import { persistedState } from 'svelte-persisted-state';

	interface UserPreferences {
		theme: 'light' | 'dark';
		fontSize: number;
	}

	const preferences = persistedState<UserPreferences>('preferences', {
		theme: 'light',
		fontSize: 16
	});

	const theme = $derived(preferences.current.theme);
	const fontSize = $derived(preferences.current.fontSize);
</script>

<div style="font-size: {fontSize}px">
	<button onclick={() => (preferences.current.theme = theme === 'light' ? 'dark' : 'light')}>
		Switch to {theme === 'light' ? 'dark' : 'light'} theme
	</button>
	<button onclick={() => (preferences.current.fontSize -= 1)}> Decrease font size </button>
	<button onclick={() => (preferences.current.fontSize += 1)}> Increase font size </button>
	<p>Current theme: {theme}</p>
	<p>Current font size: {fontSize}px</p>
</div>

Cookie Storage Example

<script lang="ts">
	import { persistedState } from 'svelte-persisted-state';

	// User session data stored in cookies (expires in 30 days)
	const userSession = persistedState(
		'user-session',
		{
			isLoggedIn: false,
			username: ''
		},
		{
			storage: 'cookie',
			cookieExpireDays: 30
		}
	);

	// Shopping cart stored in cookies (expires in 7 days)
	const cart = persistedState('shopping-cart', [], {
		storage: 'cookie',
		cookieExpireDays: 7
	});

	function login(username: string) {
		userSession.current = { isLoggedIn: true, username };
	}

	function logout() {
		userSession.current = { isLoggedIn: false, username: '' };
	}
</script>

{#if userSession.current.isLoggedIn}
	<p>Welcome back, {userSession.current.username}!</p>
	<button onclick={logout}>Logout</button>
{:else}
	<button onclick={() => login('demo-user')}>Login as Demo User</button>
{/if}

<p>Cart items: {cart.current.length}</p>

License

MIT