Layout Persistence
Save, restore, and replace layout snapshots.
Persistence is built around snapshots: save the current layout, store it in your app, and pass it back later. Move tabs or resize panels in the localStorage demo, then reload the page.
The snapshot controls show the same flow manually, which is useful when you want explicit save, reset, or restore actions instead of automatic persistence.
const defaultLayout: TileryInitialLayout<TabData> = {
type: 'group',
direction: 'horizontal',
children: [
{
type: 'panel',
id: 'notes',
size: 50,
tabs: [
{
id: 'notes-tab',
data: {
title: 'Notes',
body: 'Resize panels, then refresh to restore this layout from localStorage.',
},
},
],
},
{
type: 'panel',
id: 'preview',
size: 50,
tabs: [
{
id: 'preview-tab',
data: {
title: 'Preview',
body: 'Snapshots preserve panel sizes, tabs, behavior flags, and active tab state.',
},
},
],
},
],
};
const STORAGE_KEY = 'tilery-example-persistence';
const tileryRef = useRef<TileryController | null>(null);
const initialLayoutRef = useRef(getInitialLayout());
const handleChange = useCallback(() => {
const layout = tileryRef.current?.getLayout<TabData>();
if (!layout) return;
localStorage.setItem(STORAGE_KEY, JSON.stringify(layout));
}, []);
const reset = () => {
localStorage.removeItem(STORAGE_KEY);
initialLayoutRef.current = defaultLayout;
};
<Tilery<TabData>
ref={tileryRef as React.Ref<TileryController>}
initialLayout={initialLayoutRef.current}
onChange={handleChange}
renderTabHeader={renderHeader}
renderTabContent={renderContent}
/>
function getInitialLayout(): TileryInitialLayout<TabData> {
if (typeof window === 'undefined') return defaultLayout;
const saved = localStorage.getItem(STORAGE_KEY);
if (!saved) return defaultLayout;
try {
const parsed = JSON.parse(saved) as unknown;
return isLayoutSnapshot(parsed) ? parsed : defaultLayout;
} catch {
return defaultLayout;
}
}const snapshotLayout: TileryInitialLayout<TabData> = {
type: 'group',
direction: 'horizontal',
children: [
{
type: 'panel',
id: 'left',
size: 34,
tabs: [
{
id: 'inbox',
data: {
title: 'Inbox',
body: 'Save a snapshot, mutate the layout, then restore the saved tree.',
},
closable: false,
},
],
},
{
type: 'panel',
id: 'right',
size: 66,
tabs: [
{
id: 'details',
data: {
title: 'Details',
body: 'setLayout(snapshot) replaces the current layout explicitly.',
},
},
],
},
],
};
const tileryRef = useRef<TileryController | null>(null);
const [snapshot, setSnapshot] =
useState<TileryLayoutSnapshot<TabData> | null>(null);
const saveSnapshot = () => {
setSnapshot(tileryRef.current?.getLayout<TabData>() ?? null);
};
const restoreSnapshot = () => {
if (snapshot) tileryRef.current?.setLayout(snapshot);
};
<Tilery<TabData>
ref={tileryRef as React.Ref<TileryController>}
initialLayout={snapshotLayout}
showActionsButton={true}
renderTabHeader={renderHeader}
renderTabContent={renderContent}
/>Related
- Concepts — Understand snapshots versus runtime layout state.
- Layouts & Snapshots — See the persisted snapshot shape.