Overview
Persistent state allows your drawer to remember whether it was open or closed across page reloads. You can also persist snap point positions, providing a seamless user experience.
Basic Usage
Enable state persistence with the persistState and persistKey props:
< script >
import { Drawer , DrawerOverlay , DrawerContent } from '@abhivarde/svelte-drawer' ;
let open = $ state ( false );
</ script >
< Drawer
bind : open
persistState = { true }
persistKey = "main-drawer"
>
< DrawerOverlay class = "fixed inset-0 bg-black/40" />
< DrawerContent class = "fixed bottom-0 left-0 right-0 bg-white rounded-t-lg p-4" >
< h2 > This drawer remembers if it was open! </ h2 >
< p > Reload the page and it will restore its state. </ p >
</ DrawerContent >
</ Drawer >
persistState={true} - Enables state persistence
persistKey="main-drawer" - Unique identifier for this drawer (default: "default")
Each drawer needs a unique persistKey if you have multiple drawers with persistence
Persisting Snap Points
When using snap points, you can also persist the current snap position:
< script >
import { Drawer , DrawerOverlay , DrawerContent , DrawerHandle } from '@abhivarde/svelte-drawer' ;
let open = $ state ( false );
let activeSnapPoint = $ state ( undefined );
</ script >
< Drawer
bind : open
snapPoints = { [ 0.25 , 0.5 , 0.9 ] }
bind : activeSnapPoint
persistState = { true }
persistKey = "snap-drawer"
persistSnapPoint = { true }
>
< DrawerOverlay class = "fixed inset-0 bg-black/40" />
< DrawerContent class = "fixed bottom-0 left-0 right-0 bg-white rounded-t-lg p-4" >
< DrawerHandle class = "mb-8" />
< h2 > Position is saved too! </ h2 >
< p > The snap point will be restored on reload. </ p >
</ DrawerContent >
</ Drawer >
persistSnapPoint={true} - Enables snap point persistence
Requires persistState={true} to be enabled
Programmatic State Management
You can use utility functions to manually manage drawer state:
Clear Saved State
< script >
import { Drawer , DrawerOverlay , DrawerContent , clearDrawerState } from '@abhivarde/svelte-drawer' ;
let open = $ state ( false );
function resetDrawer () {
clearDrawerState ( 'main-drawer' );
// Drawer will reset to default state on next load
}
</ script >
< button onclick = { resetDrawer } > Reset Drawer State </ button >
< Drawer bind : open persistState = { true } persistKey = "main-drawer" >
< DrawerOverlay class = "fixed inset-0 bg-black/40" />
< DrawerContent class = "fixed bottom-0 left-0 right-0 bg-white rounded-t-lg p-4" >
< h2 > Drawer Content </ h2 >
</ DrawerContent >
</ Drawer >
Save State Manually
< script >
import { saveDrawerState } from '@abhivarde/svelte-drawer' ;
function saveCustomState () {
saveDrawerState ( 'my-drawer' , true , 0.5 );
// Saves: open=true, snapPoint=0.5
}
</ script >
Load State Manually
< script >
import { loadDrawerState } from '@abhivarde/svelte-drawer' ;
function checkSavedState () {
const state = loadDrawerState ( 'my-drawer' );
if ( state ) {
console . log ( 'Drawer was open:' , state . open );
console . log ( 'Snap point:' , state . snapPoint );
}
}
</ script >
Implementation Details
State is saved to localStorage with the key format svelte-drawer-{persistKey}:
/home/daytona/workspace/source/src/lib/utils/storage.ts:1-6
interface DrawerState {
open : boolean ;
snapPoint ?: number ;
}
const STORAGE_PREFIX = "svelte-drawer-" ;
Save Function
/home/daytona/workspace/source/src/lib/utils/storage.ts:8-25
export function saveDrawerState (
key : string ,
open : boolean ,
snapPoint ?: number
) : void {
if ( typeof window === "undefined" ) return ;
try {
const state : DrawerState = { open };
if ( snapPoint !== undefined ) {
state . snapPoint = snapPoint ;
}
localStorage . setItem ( ` ${ STORAGE_PREFIX }${ key } ` , JSON . stringify ( state ));
} catch ( error ) {
console . warn ( "Failed to save drawer state:" , error );
}
}
Load Function
/home/daytona/workspace/source/src/lib/utils/storage.ts:27-39
export function loadDrawerState ( key : string ) : DrawerState | null {
if ( typeof window === "undefined" ) return null ;
try {
const stored = localStorage . getItem ( ` ${ STORAGE_PREFIX }${ key } ` );
if ( ! stored ) return null ;
return JSON . parse ( stored ) as DrawerState ;
} catch ( error ) {
console . warn ( "Failed to load drawer state:" , error );
return null ;
}
}
Clear Function
/home/daytona/workspace/source/src/lib/utils/storage.ts:41-49
export function clearDrawerState ( key : string ) : void {
if ( typeof window === "undefined" ) return ;
try {
localStorage . removeItem ( ` ${ STORAGE_PREFIX }${ key } ` );
} catch ( error ) {
console . warn ( "Failed to clear drawer state:" , error );
}
}
Automatic Saving
The drawer automatically saves state when changes occur:
/home/daytona/workspace/source/src/lib/components/Drawer.svelte:65-73
$effect (() => {
if ( persistState && stateLoaded ) {
saveDrawerState (
persistKey ,
open ,
persistSnapPoint ? activeSnapPoint : undefined
);
}
});
Automatic Loading
State is loaded when the component mounts:
/home/daytona/workspace/source/src/lib/components/Drawer.svelte:39-56
onMount (() => {
if ( persistState && ! stateLoaded ) {
const savedState = loadDrawerState ( persistKey );
if ( savedState ) {
open = savedState . open ;
if (
persistSnapPoint &&
savedState . snapPoint !== undefined &&
snapPoints
) {
activeSnapPoint = savedState . snapPoint ;
}
}
stateLoaded = true ;
}
Multiple Drawers with Persistence
You can have multiple drawers with different persistence keys:
< script >
let drawer1Open = $ state ( false );
let drawer2Open = $ state ( false );
</ script >
< Drawer bind : open = { drawer1Open } persistState = { true } persistKey = "drawer-1" >
<!-- First drawer -->
</ Drawer >
< Drawer bind : open = { drawer2Open } persistState = { true } persistKey = "drawer-2" >
<!-- Second drawer - independent state -->
</ Drawer >
Privacy Considerations
State is stored in localStorage, which persists until manually cleared. Users in incognito/private mode may not have persistence.
To respect user privacy, you might want to add a setting:
< script >
let open = $ state ( false );
let rememberState = $ state ( true );
</ script >
< Drawer
bind : open
persistState = { rememberState }
persistKey = "main-drawer"
>
< DrawerContent class = " ... " >
< label >
< input type = "checkbox" bind : checked = { rememberState } />
Remember drawer state
</ label >
</ DrawerContent >
</ Drawer >
Use Cases
Settings Panel
< Drawer
persistState = { true }
persistKey = "settings-panel"
direction = "right"
>
<!-- User's settings panel stays open if they had it open -->
</ Drawer >
Navigation Drawer
< Drawer
persistState = { true }
persistKey = "nav-drawer"
direction = "left"
>
<!-- Navigation drawer remembers state -->
</ Drawer >
Bottom Sheet with Preferred Height
< Drawer
persistState = { true }
persistKey = "content-sheet"
snapPoints = { [ 0.3 , 0.6 , 0.9 ] }
persistSnapPoint = { true }
>
<!-- Remembers user's preferred height -->
</ Drawer >
Storage Utilities API
saveDrawerState
saveDrawerState ( key : string , open : boolean , snapPoint ?: number ): void
Manually save drawer state to localStorage.
loadDrawerState
loadDrawerState ( key : string ): DrawerState | null
Manually load drawer state from localStorage. Returns null if no state exists.
clearDrawerState
clearDrawerState ( key : string ): void
Remove saved drawer state from localStorage.
Best Practices
Use descriptive persistKey values like "settings-drawer" instead of generic names
Provide a way to reset/clear state for user convenience
Persistence works in SSR environments - it safely checks for window before accessing localStorage
Don’t rely on persistence for critical functionality - treat it as a UX enhancement
API Reference Persistence props documentation
Snap Points Learn about persisting snap positions