Bringing Signals to Lit Labs

The new Signals package integrates the TC39 Signals proposal with Lit

Photo of Lit Team
Lit Team

Announcing @lit-labs/signals: Integrating the TC39 Signals Proposal with Lit

We’re thrilled to announce the release of our newest Lit Labs package, @lit-labs/signals, which integrates the polyfill for the exciting new TC39 Signals Proposal directly with Lit. This package provides a powerful, reactive way to manage state in your web applications by allowing you to use shared, observable signals that automatically update components when their values change.

Signals are quickly becoming a core feature in the JavaScript ecosystem, and the TC39 proposal has the potential to unify signals and how we manage state and reactivity across various libraries and frameworks.

Though the proposal is in its early stages, you can start experimenting with signals and @lit-labs/signals today to see how building components and apps on a universal reactivity primitive might work for you.

What Are Signals?

In simple terms, signals are observable data structures that hold values or computations. When the value of a signal changes, all components or parts of your app that depend on it are automatically notified and updated. This is particularly useful in UIs where multiple components might need to share and react to changes in state.

Key Benefits of Standards-Based Signals

  1. Shared observable state: Signals are great for managing state shared across multiple components. If one component updates a signal, all others using it will automatically update as well.
  2. Pinpoint updates: Signals enable precisely targeted re-renders, potentially improving performance by processing only bindings whose signal- backed values have changed, skipping other bindings in the same templates.
  3. Interoperability: The standardization of signals means different libraries and frameworks can use signals interoperably, reducing the need for complex adapters and improving compatibility.

Why We're Excited About @lit-labs/signals

Lit is already known for its lightweight, performant, and declarative approach to building web components. But Lit is tightly focused on helping you build reusable, encapsulated components. Lit is not a framework and does not precribe how to model your data or make it observable.

Lit's reactivity is by default relatively shallow. Components automatically update when their own reactive properties change, but not when nested properties change. Responding to deep property changes has either required manual update requests, or the integration of a state management system like Redux or MobX.

Signals give us many of the same deep observability abilities as these state management systems, but with a smaller, simpler API, and the potential to be a common standard across a large ecosystem of utilies, components, and frameworks.

Signals aren't entirely new to Lit. We previously released the @lit-labs/preact-signals package, but we were somewhat unsatisfied with the need to build a Lit integration for a specific signals library, and potentially every signals library that Lit developers might want to use.

Standardized signals in JavaScript would let us build just one integration (and eventually add signals support directly in Lit's core), and enable interop between signal-using libraries in the same spirit of the interop that web components enable.

The new @lit-labs/signals package makes it super easy to use the new signals proposal from within your Lit components.

Let’s dive into a few examples...

Example 1: A Shared Counter

Here’s a simple example of a shared counter using @lit-labs/signals. To enable signal-based reactivity in this component, we just use the SignalWatcher mixin in our Custom Element definition; any signals we read from will automatically be observed, triggering updates whenever their values change:

With this approach, any number of <shared-counter> components can be added to the DOM, and all will reflect the same counter value, automatically updating when the signal changes.

You can also see this example in the Lit Playground.

Example 2: Pinpoint DOM Updates

Using the watch directive, we can also achieve pinpoint updates targeting individual bindings rather than an entire component:

Here, only the binding displaying the count is processed when the signal changes, skipping unnecessary work and improving performance.

Future Work

This is just the beginning or our exploration of signals integration for Lit. Coming soon, we will add more utilities to @lit-labs/signals for incrementally rendering changes from collections, easily running side-effects in components, and using signals for reactive properties.

Eventually—as the proposed standard progresses and we gain experience using signals in Lit—signals will likely become part of the core library.

The Lit team is working closely with the TC39 Signals Proposal champions to ensure that signals work great for Lit, web components, and plain-DOM use cases. We can't overstate how much potential we see in signals to form an interoperable reactivity primitive that works across libraries and components without requiring a centralized framework.

Try It Out and Give Feedback

We’re eager to get feedback from the community as you experiment with this new package. As part of the Lit Labs family, @lit-labs/signals is still experimental and may undergo significant changes based on user feedback and advancements in the TC39 Signals Proposal.

To get started, simply install the package:

We’d love to hear your thoughts, so please try it out, and let us know how it works for you.

We’re excited to see what you’ll build with signals and how they will shape the future of state management in web applications!

Thanks!

-The Lit Team

Read more posts