Skip to content

lit-ui-router-signals ​

NPM VersionGitHub Release

lit-ui-router-signals provides TC39 Signals bindings for lit-ui-router: ReactiveControllers that watch the ui-router-signals mirror of the router's state and update their host when a selected value changes.

It registers no custom elements and adds no routing behavior. It has the shape of the Effect and MobX bindings:

SignalsMobXEffect
RouterSignals (ui-router-signals)RouterStore (ui-router-mobx)routeRef (ui-router-effect)
SignalControllerReactionControllerRefController
RouterSignalControllerRouterReactionControllerRouterRefController

Installation ​

bash
npm install lit-ui-router-signals ui-router-signals signal-polyfill

lit-ui-router, ui-router-signals, lit, and @uirouter/core are peer dependencies, and signal-polyfill is a peer of ui-router-signals.

Quick start ​

ts
import { html, LitElement } from 'lit';
import { RouterSignalController } from 'lit-ui-router-signals';

class AppNav extends LitElement {
  // Re-renders only when the selection flips, not on every transition.
  private inbox = new RouterSignalController(this, (signals) =>
    signals.route.get().includes('inbox.**'),
  );

  render() {
    return html`...${this.inbox.value ? 'Inbox is open' : ''}...`;
  }
}

No router configuration is required: the controller discovers the router from the enclosing <ui-router> element when the host connects, and RouterSignals.for attaches its single transition hook on first use.

The pieces ​

RouterSignalController ​

RouterSignalController watches the RouterSignals of a router and exposes the selector's result as .value. The router comes from the router option (a router or a thunk), a withRouterSync scope at construction, or the nearest provider on hostConnected, as the Effect and MobX router controllers find theirs. setRouter() hands it a router later.

SignalController ​

SignalController is the generic primitive: it watches any selector over signals while the host is connected, and calls requestUpdate() only when the selected value changes under equals (default Object.is).

Both take initialValue, equals and onChange options. Changes arrive in a microtask after the source changes: a watcher's notify callback may not read signals, so it schedules the read.

Lifecycle safety ​

Watching starts in hostConnected and stops in hostDisconnected. The selector runs on every (re)connect, so a component that re-enters the DOM renders current values.

@lit-labs/signals ​

@lit-labs/signals builds on the same signal-polyfill, so a SignalWatcher element tracks the RouterSignals fields it reads in render() without a controller. Both need one copy of signal-polyfill in the bundle; two copies keep two separate signal graphs.

See it in a real app ​

The Signals sample app is a complete application built on RouterSignalController and @lit-labs/signals. It is behaviorally identical to the vanilla sample app (which uses TransitionController), the MobX sample app and the Effect sample app, so the four codebases can be compared file-by-file to see exactly what the Signals idiom changes.

Further reading ​