All components

State Flow

Graph-driven diagram for visualizing async UI state machines - idle, loading, success, and error paths with linear or expanded layout modes.

API Request Status
Simulated fetch lifecycle with auto-reset - linear mode for happy-path status indicators.

API request

Linear mode focuses on the happy path - ideal for fetch/submit status indicators that auto-reset after completion.

IdleClick to send request
>
LoadingCalling API...
>
SuccessResponse received
1"use client";
2
3import { useEffect, useRef, useState } from "react";
4import {
5 StateFlowDiagram,
6 type StateFlowState,
7} from "@/registry/ui/state-flow";
8import { MotionButton } from "./motion-button";
9
10export function StateFlowApiRequestStatusExample() {
11 const [state, setState] = useState<StateFlowState>("idle");
12 const resetTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
13
14 useEffect(() => {
15 return () => {
16 if (resetTimerRef.current) clearTimeout(resetTimerRef.current);
17 };
18 }, []);
19
20 const simulateRequest = async () => {
21 if (resetTimerRef.current) clearTimeout(resetTimerRef.current);
22
23 setState("loading");
24
25 await new Promise((resolve) => setTimeout(resolve, 1200));
26
27 const success = Math.random() > 0.3;
28 setState(success ? "success" : "error");
29
30 resetTimerRef.current = setTimeout(() => setState("idle"), 2000);
31 };
32
33 return (
34 <div className="space-y-6 rounded-lg border border-border p-6">
35 <div className="space-y-1 text-center">
36 <p className="text-sm font-medium text-foreground">API request</p>
37 <p className="text-xs text-muted-foreground">
38 Linear mode focuses on the happy path - ideal for fetch/submit status
39 indicators that auto-reset after completion.
40 </p>
41 </div>
42
43 <StateFlowDiagram
44 currentState={state}
45 mode="linear"
46 labels={{
47 idle: "Click to send request",
48 loading: "Calling API...",
49 success: "Response received",
50 error: "Request failed",
51 }}
52 />
53
54 <div className="flex justify-center">
55 <MotionButton
56 variant="info"
57 onClick={simulateRequest}
58 disabled={state === "loading"}
59 >
60 Trigger Request
61 </MotionButton>
62 </div>
63 </div>
64 );
65}
Job Queue Visualizer
Background worker with success/failure branches - expanded mode for queue and retry flows.

Background job

Expanded mode shows the success path and failure branch together - useful for queue workers and retry flows.

IdleQueue idle
>
LoadingWorker processing job
>
SuccessJob completed
v
ErrorJob failed / retry needed
1"use client";
2
3import { useEffect, useRef, useState } from "react";
4import {
5 StateFlowDiagram,
6 type StateFlowState,
7} from "@/registry/ui/state-flow";
8import { MotionButton } from "./motion-button";
9
10export function StateFlowJobQueueVisualizerExample() {
11 const [state, setState] = useState<StateFlowState>("idle");
12 const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
13
14 useEffect(() => {
15 return () => {
16 if (timerRef.current) clearTimeout(timerRef.current);
17 };
18 }, []);
19
20 const runJob = () => {
21 if (timerRef.current) clearTimeout(timerRef.current);
22
23 setState("loading");
24
25 timerRef.current = setTimeout(() => {
26 setState(Math.random() < 0.6 ? "success" : "error");
27 }, 1500);
28 };
29
30 return (
31 <div className="space-y-6 rounded-lg border border-border bg-slate-950 p-6">
32 <div className="space-y-1 text-center">
33 <p className="text-sm font-medium text-foreground">Background job</p>
34 <p className="text-xs text-muted-foreground">
35 Expanded mode shows the success path and failure branch together -
36 useful for queue workers and retry flows.
37 </p>
38 </div>
39
40 <StateFlowDiagram
41 currentState={state}
42 mode="expanded"
43 labels={{
44 idle: "Queue idle",
45 loading: "Worker processing job",
46 success: "Job completed",
47 error: "Job failed / retry needed",
48 }}
49 />
50
51 <div className="flex flex-wrap justify-center gap-3">
52 <MotionButton
53 variant="success"
54 onClick={runJob}
55 disabled={state === "loading"}
56 >
57 Run Job
58 </MotionButton>
59
60 <MotionButton variant="neutral" onClick={() => setState("idle")}>
61 Reset
62 </MotionButton>
63 </div>
64 </div>
65 );
66}

Installation & source

Install via the shadcn CLI or copy the registry files manually.

bash
npx shadcn@latest add @tt-ui/state-flow

Props

NameTypeDefaultDescription
currentState"idle" | "loading" | "success" | "error"RequiredThe active state in the flow
mode"linear" | "expanded""linear"Linear shows the main chain only; expanded stacks branch nodes (e.g. error paths)
labels{ idle?: string; loading?: string; success?: string; error?: string }undefinedOptional per-state description overrides under each node