---
title: "Firelight.Signals"
description: "Share reactive state between any components on the page, with updates targeted to the template parts that use it. F# bindings for @lit-labs/signals."
---

# Firelight.Signals

Reactive state that lives outside your components, shared by any component that reads it.

- [Lit docs: Signals](https://lit.dev/docs/data/signals/)
- [NuGet 0.3.0](https://www.nuget.org/packages/Firelight.Signals/0.3.0)
- [Source](https://github.com/roboz0r/Firelight/tree/main/src/Firelight.Signals)

## 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.defineElement`
  re-renders when a signal it read while rendering changes. This needs no providers, context keys or
  manual subscriptions.
- **Derived state:** `computed` creates 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.

```fsharp
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"
```

```html
<my-click-button></my-click-button>
<my-click-total></my-click-total>
```

## Install

```sh
dotnet add package Firelight.Signals
npm install @lit-labs/signals
```
