Skip to content

Widget mode

Reactive Route can be detached from window.history and used in widget mode, fully embedding into websites without iframes. This page shows two working widgets at once: one built with Solid.js and native reactivity (13.3 KB), and another with Preact and Observable (11.85 KB). Both use the corresponding code from Examples, replacing await router.init(location.href) with this code:

ts
// import { autorun } from 'kr-observable';
import { createRenderEffect } from 'solid-js';

router.historySyncStop();

await router.init(localStorage.getItem('WIDGET_URL') || '/');

// save to external storage
createRenderEffect(() => { // autorun(() => {
  const currentUrl = router.activeName
    ? router.stateToUrl(router.state[router.activeName])
    : '/';

  localStorage.setItem('WIDGET_URL', currentUrl);
});

// restore from external storage
window.addEventListener('storage', (event) => {
  if (event.key === 'WIDGET_URL') {
    router.redirect(router.urlToState(event.newValue || '/'));
  }
});

You only need to listen for the 'storage' event if you plan to control the widget from outside: it is enough to write a new URL to localStorage and in some cases trigger this event manually according to the browser specification. The two buttons below are native VitePress (Vue) controls that drive both widgets at once and execute the following code on click:

ts
function setWidgetUrl(url: string) {
  localStorage.setItem('WIDGET_URL', url);

  window.dispatchEvent(
    new StorageEvent('storage', {
      key: 'WIDGET_URL',
      newValue: url,
      storageArea: localStorage,
    })
  );
}

The second example below uses a different UI stack and reactivity model but stays synchronized on the same page through the same external controls.

Naturally, you can embed large websites and admin panels, as well as design microfrontends. The main thing is to ensure isolation of styles and variables by configuring the bundler correctly.

No AI participated in the development. MIT License