SeqDia

Interactive sequence diagrams for React

Model actors as a tree with collapsible groups. Messages route to visible leaves—expand a group to reveal child actors, collapse to roll messages up to the parent.

GitHub

Live example

Click actor headers to expand/collapse groups. Try the controls to see highlighting and selection in action.

Start checkoutbrowser → frontend
Authenticatefrontend → auth
Load profileauth → database
Profile readydatabase → auth
Auth completeauth → frontend
Create intentfrontend → payments
Validate cartpayments
Persist intentpayments → database
Intent storeddatabase → payments
Confirmpayments → frontend
Render receiptfrontend → browser

Quick start

Install and render a diagram in minutes.

Install

pnpm add seqdia

Requires react and react-dom as peer dependencies. Tailwind CSS is expected for styling.

import {
  SequenceDiagram,
  useSequenceController,
  defineLeafDiagram,
} from "seqdia";

const model = defineLeafDiagram({
  actors: [
    { actorId: "a", label: "Service A" },
    { actorId: "b", label: "Service B" },
  ],
  messages: [
    { messageId: "m1", fromActorId: "a",
      toActorId: "b", label: "Request" },
  ],
});

function Diagram() {
  const controller = useSequenceController(model);
  return (
    <SequenceDiagram
      model={model}
      controller={controller}
    />
  );
}

Controller API

The controller manages diagram state. Create one with useSequenceController(model).

Expansion

  • expandActor(id)
  • collapseActor(id)
  • toggleActorExpansion(id)
  • setExpandedActors(Set)

Highlighting

  • highlightActors(ids)
  • highlightMessages(ids)
  • clearHighlights()

Transient emphasis, typically on hover

Selection

  • selectActors(ids)
  • selectMessages(ids)
  • toggleActorSelection(id)
  • toggleMessageSelection(id)
  • clearSelection()

Persistent state, typically on click

const controller = useSequenceController(model);

// Expand/collapse groups
controller.expandActor("auth");
controller.collapseActor("payments");
controller.toggleActorExpansion("auth");

// Highlight actors or messages (visual emphasis)
controller.highlightActors(["auth", "payments"]);
controller.highlightMessages(["auth-session", "intent"]);
controller.clearHighlights();

// Select actors or messages (persistent state)
controller.selectMessages(["confirm"]);
controller.toggleActorSelection("database");
controller.clearSelection();

// Access current state
const { highlight, selection, expandedActors } = controller.state;

Custom rendering

Use render props to fully customize actors and messages.

<SequenceDiagram
  model={model}
  controller={controller}
  getActorStyle={(actor) => ({
    color: palette[actor.actorId],
  })}
  getMessageStyle={(message) => ({
    strokeColor: palette[message.fromActorId],
  })}
  renderActor={({ actor, buttonProps, highlighted }) => (
    <button {...buttonProps} className={cn("btn", highlighted && "ring-2")}>
      {actor.label}
    </button>
  )}
  renderMessage={({ resolved, messageProps }) => (
    <div {...messageProps}>
      <MessageArrow direction={resolved.direction} stroke="#333" />
      <span>{resolved.message.label}</span>
    </div>
  )}
  onActorClick={(id) => console.log("Actor:", id)}
  onMessageClick={(id) => console.log("Message:", id)}
/>