Firelight.Signals
Reactive state that lives outside your components, shared by any component that reads it.
Why use it
Lit's context passes state through the DOM hierarchy with providers and consumers. Signals keep reactive state outside the DOM.
A signal is a standalone value that tracks who reads it:
- Subscriptions without wiring: any component registered with
LitSignals.defineElementre-renders when a signal it read while rendering changes. This needs no providers, context keys or manual subscriptions. - Derived state:
computedcreates values from other signals. They stay up to date, compute lazily and cache their results. - Surgical updates: with
LitSignals.html, a signal interpolated into a template updates only that binding, instead of re-rendering the whole component (as long as the render doesn't also read the signal elsewhere).
Lit's signals are based on the TC39 Signals proposal and are still experimental.
Example
The button and the total are separate elements on this page, with no shared parent, property or event between them.
module Snippets.SharedSignal
open Fable.Core
open Firelight
open Firelight.Signals
open type LitSignals
// State outside any component. Every component that reads it stays in sync.
let clicks = signal 0
let doubled = computed (fun () -> clicks.get () * 2)
[<AttachMembers>]
type ClickButton() =
inherit LitElement()
static member styles =
Lit.css $$"""button { font: inherit; padding: 0.4rem 0.9rem; cursor: pointer; }"""
override _.render() =
html $"""<button @click={fun _ -> clicks.set (clicks.get () + 1)}>Click me</button>"""
// A separate component, with no parent, property or event connecting it to the button.
// Interpolated signals update just their part of the template.
[<AttachMembers>]
type ClickTotal() =
inherit LitElement()
override _.render() =
html $"""<p>{clicks} clicks, doubled is {doubled}</p>"""
defineElement<ClickButton> "my-click-button"
defineElement<ClickTotal> "my-click-total"
0 clicks, doubled is 0
Install
dotnet add package Firelight.Signals
npm install @lit-labs/signals