Skip to content

Widget mode

Reactive Route can be detached from window.history and used in widget mode, fully embedding into websites without iframes. Here, the Solid.js variant from Examples was taken, replacing await router.init(location.href) with this code:

ts
import { createRenderEffect } from 'solid-js';

router.historySyncStop();

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

// save to external storage
createRenderEffect(() => {
  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. Thus, the two buttons below are native VitePress (Vue) buttons and on click execute the following code:

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

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

The compressed js bundle size for this widget is 13.3 KB, while it still contains a full reactivity and rendering system plus Reactive Route. Naturally, you can embed several widgets on different stacks, and even 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