Syed Hasnain

Connection State

Component 1

About

A resumable stream status with a retry countdown, attempt count, Retry now, and a collapsible connection log.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Connection State to your project and fits it to your theme.

Code

How Connection State is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

import * as React from 'react'
import {
  ConnectionState,
  type ConnectionEvent,
  type ConnectionStatus,
} from '@/components/ui/connection-state'

const delay = 4

interface Frame {
  attempt?: number
  event?: Omit<ConnectionEvent, 'id'>
  retryIn?: number
  state: ConnectionStatus
  wait: number
}

const frames: Frame[] = [
  {
    state: 'connected',
    wait: 1600,
    event: { label: 'Streaming response', state: 'connected', time: '14:02:11' },
  },
  {
    state: 'offline',
    wait: 1400,
    event: { label: 'Socket closed by network', state: 'offline', time: '14:02:13' },
  },
  ...Array.from({ length: delay }, (_, index) => ({
    state: 'reconnecting' as const,
    attempt: 1,
    retryIn: delay - index,
    wait: 1000,
    event:
      index === 0
        ? { label: 'Retrying with backoff', state: 'reconnecting' as const, time: '14:02:14' }
        : undefined,
  })),
  { state: 'reconnecting', attempt: 2, wait: 1400 },
  {
    state: 'reconnected',
    wait: 3200,
    event: { label: 'Resumed from token 1,284', state: 'reconnected', time: '14:02:19' },
  },
]

export default function Demo() {
  const [index, setIndex] = React.useState(3)
  const frame = frames[index]
  const events = frames
    .slice(0, index + 1)
    .flatMap((item, position) => (item.event ? [{ ...item.event, id: String(position) }] : []))
    .reverse()

  React.useEffect(() => {
    const timer = setTimeout(() => setIndex((value) => (value + 1) % frames.length), frame.wait)
    return () => clearTimeout(timer)
  }, [frame.wait])

  return (
    <ConnectionState
      attempt={frame.attempt}
      className="w-full max-w-md"
      defaultLogOpen
      detail={
        frame.state === 'reconnected'
          ? 'No messages were lost'
          : 'The run continues safely on the server'
      }
      events={events}
      maxAttempts={5}
      onRetry={() => setIndex(frames.length - 2)}
      retryDelay={delay}
      retryIn={frame.retryIn}
      state={frame.state}
    />
  )
}

Dependencies

More by Syed Hasnain

View all
  • Color Picker

    Color Picker

    80
  • Cost Meter

    Cost Meter

    29
  • Quota Banner

    Quota Banner

    21
  • Message Scroller

    Message Scroller

    21
  • Commit

    Commit

    17
  • Image Generation Loader

    Image Generation Loader

    15
  • Attachments

    Attachments

    15
  • Citations

    Citations

    14

Explore more

Part of Pasta UI — browse the full library on 21st.dev.