📖Browse Tutorials▼

Saving State & Layouts

You’ve build a marvellous app, configured your layout and the user arranged things just the way he likes. Great!

But the next time he opens the app he wants to find everything just the way he left it. Or (if you’re feeling fancy) choose from a number of saved layouts.

Strelit Layout offers a powerful persistence mechanism for that. Not only every aspect of the layout, also the state of the components within it can be converted into a serialisable object that can be saved to a database, to local storage or wherever else your heart desires.

Here’s how it works:

Creating the Layout

For this tutorial we'll use the layout created in getting-started.

const config = {
  root: {
    type: 'row',
    content: [
      {
        type: 'component',
        componentType: 'testComponent',
        componentState: { label: 'A' },
      },
      {
        type: 'column',
        content: [
          {
            type: 'component',
            componentType: 'testComponent',
            componentState: { label: 'B' },
          },
          {
            type: 'component',
            componentType: 'testComponent',
            componentState: { label: 'C' },
          },
        ],
      },
    ],
  },
};

Initialize your layout on the viewport element:

const containerEl = document.getElementById('layoutContainer');
const myLayout = new StrelitLayout(containerEl);

Listening for State Changes

Your layout instance and all items within it emit events. The event we're interested in is called stateChanged. It is emitted whenever an interaction modifies the saveable layout state (e.g., resizing panes, docking or closing tabs).

myLayout.on('stateChanged', () => {
  // Save serialized layout state
  const state = myLayout.saveLayout();
  localStorage.setItem('savedState', JSON.stringify(state));
});

The layout state is serialized into a clean, JSON-compatible object by calling myLayout.saveLayout() (note: toConfig() is maintained as an alias).

Serialising entire layouts can be compute-intensive during rapid splitter drags. In production, debounce your stateChanged listener or trigger saves on explicit user actions.

Creating Layouts from Saved States

When a user returns to the application, check localStorage for a previously saved configuration. Since saveLayout() outputs aResolvedLayoutConfig (with calculated numeric sizes), use the built-in helper createLayoutConfigFromResolved() to convert the snapshot back into a valid LayoutConfig before passing it to loadLayout():

import { StrelitLayout, createLayoutConfigFromResolved } from 'strelit-ui-kit';

const savedState = localStorage.getItem('savedState');
const initialConfig = savedState
  ? createLayoutConfigFromResolved(JSON.parse(savedState))
  : defaultConfig;

// Load configuration into the layout instance
myLayout.loadLayout(initialConfig);

Saving Component States with stateRequestEvent

While Strelit automatically serializes tree structure, dimensions, and active tabs, component-specific data (such as form inputs, filters, or cursor positions) is requested dynamically when saveLayout() runs.

Instead of imperative state calls, assign a callback function to container.stateRequestEvent. When Strelit serializes the layout tree, it executes this callback to retrieve your component’s up-to-date state:

myLayout.registerComponentFactoryFunction('testComponent', (container, itemConfig) => {
  // Read initial state (either from default config or restored session)
  const state = itemConfig.componentState || { label: '' };

  // Create native input element
  const input = document.createElement('input');
  input.type = 'text';
  input.value = state.label || '';
  input.placeholder = 'Type something to persist...';

  // Mount to container element
  container.element.appendChild(input);

  // Register state serialization provider
  container.stateRequestEvent = () => {
    return {
      label: input.value,
    };
  };

  // Optional: Notify layout on immediate change so stateChanged fires
  input.addEventListener('input', () => {
    myLayout.emitBaseBubblingEvent('stateChanged');
  });
});

The Result

Interactive Example: Saving State

Inspect, fork, and test this complete layout implementation live on CodePen:

Whether you are building complex multi-screen trading terminals, enterprise data workspaces, or migrating from legacy layout engines, our team and community are here to help.

Open an Issue on GitHub →