live_interaction_contracts

Copy Markdown View Source

Executable interaction contracts for Phoenix LiveView.

This package checks whether browser-native interaction state survives LiveView patches. It ships a conformance harness, a delegation ledger, and a small set of unstyled reference components that are backed by those contracts.

Use it when you need to know whether a popover, menu, tooltip, select, combobox, dialog adapter, focus handoff, or async query shell is safe under LiveView DOM patching.

Why this exists

LiveView gives the server authority over rendered HTML, but many interaction machines keep their state in the browser: top-layer popovers, active descendants, focus, selection, pending input, and listbox shells.

The hard failures happen when both sides think they own the same state. A patch replaces a node, a client hook rebinds, the server renders stale results, or the browser keeps state that the server cannot observe.

live_interaction_contracts turns those cases into executable contracts. Each green claim is backed by browser tests across Chromium, Firefox, and WebKit. Amber and unknown cases stay explicit.

What ships

  • A Mix task that runs the conformance harness against real browsers.
  • A generated delegation ledger that classifies each state machine as green, amber, red, or unknown.
  • Reference components for <.popover>, <.tooltip>, <.menu>, <.select>, and <.combobox>.
  • A LiveInteractionContracts.Channel helper for monotonic async query results.
  • Contract documents that define the state ownership rules.

The components are intentionally unstyled. They are reference primitives, not a finished UI kit. The future UI kit direction is Temper UI; this package is the proof layer underneath it.

Install

For harness, ledger, and CI use:

{:live_interaction_contracts, "~> 1.0", only: [:dev, :test], runtime: false}

If you also use the reference components at runtime:

{:live_interaction_contracts, "~> 1.0"}

The harness requires elixir, node, and Playwright browsers:

npx playwright install chromium firefox webkit

The reference components require Phoenix LiveView 1.1 or later. Their client JS ships as Phoenix colocated hooks. After mix compile, register the extracted hooks in your app.js:

import {hooks as licHooks} from "phoenix-colocated/live_interaction_contracts";

new LiveSocket("/live", Socket, {hooks: {...hooks, ...licHooks}});

Reference component example

defmodule MyAppWeb.Demo do
  use Phoenix.Component
  use LiveInteractionContracts.Components

  def demo(assigns) do
    ~H"""
    <.popover id="demo" placement="bottom">
      <:trigger>Open</:trigger>
      <:content>Patch-safe by contract.</:content>
    </.popover>
    """
  end
end

Run the harness

Run these commands from your Phoenix project:

# all stable browser engines
mix live_interaction_contracts.test

# one browser
mix live_interaction_contracts.test --browser chromium

# one suite
mix live_interaction_contracts.test --suite combobox

# early warning against LiveView main
mix live_interaction_contracts.test --lv "github:phoenixframework/phoenix_live_view#main"

# regenerate the delegation ledger
mix live_interaction_contracts.ledger

# advisory app audit for patch-safety and dual-write risk
mix live_interaction_contracts.audit --path /path/to/app

# compare two harness result sets
mix live_interaction_contracts.compare --a before.json --b after.json

By default, the harness tests against your project's LiveView version.

Current v1 coverage

Green reference machines:

  • Popover
  • Tooltip
  • Menu
  • Select
  • Combobox
  • Cursor coordination
  • Versioned async query channel

Amber:

  • Dialog adapter, with documented restrictions.

Unknown:

  • Native select popup open-state.
  • Real-device IME behavior.
  • SPEC.md: v1 frozen scope and project claims.
  • KERNEL.md: the state ownership model.
  • CONFORMANCE.md: harness and CI behavior.
  • BUILDING_COMPONENTS.md: how to add the next contract-backed component.
  • PROJECT_MAP.md: where the detailed evidence lives in this repository.