Composables

useRealtimeConnection

Monitor and control the WebSocket connection.

useRealtimeConnection

Monitor and control the WebSocket connection status. Use this composable to show connection indicators, handle reconnection logic, or manually control the connection.

Usage

<script setup>
const { connected, status } = useRealtimeConnection()
</script>

<template>
  <span :class="connected ? 'text-green-500' : 'text-red-500'">
    {{ status }}
  </span>
</template>

Type Signature

function useRealtimeConnection(
  options?: UseRealtimeConnectionOptions
): UseRealtimeConnectionReturn

Options

interface UseRealtimeConnectionOptions {
  onConnected?: () => void
  onDisconnected?: (reason: string) => void
  onReconnecting?: (attempt: number) => void
  onReconnected?: (attempt: number) => void
  onReconnectFailed?: () => void
  onError?: (error: Error) => void
}

Event Callbacks

CallbackDescription
onConnectedCalled when connection is established
onDisconnectedCalled when disconnected, with disconnect reason
onReconnectingCalled on each reconnection attempt, with attempt number
onReconnectedCalled after successful reconnection, with total attempts
onReconnectFailedCalled when all reconnection attempts have failed
onErrorCalled on connection errors

Return Value

interface UseRealtimeConnectionReturn {
  // Reactive state
  connected: Readonly<Ref<boolean>>
  status: Readonly<Ref<ConnectionStatus>>
  attempt: Readonly<Ref<number | undefined>>

  // Methods
  connect: () => void
  disconnect: () => void

  // Raw socket
  socket: Socket
}

type ConnectionStatus = 'connected' | 'disconnected' | 'connecting' | 'reconnecting'

connected

A readonly boolean ref indicating if the socket is currently connected:

const { connected } = useRealtimeConnection()

watchEffect(() => {
  if (connected.value) {
    console.log('Online')
  } else {
    console.log('Offline')
  }
})

status

A readonly ref with the current connection status:

StatusDescription
connectedSuccessfully connected to the server
disconnectedNot connected to the server
connectingInitial connection in progress
reconnectingAttempting to reconnect after disconnect
const { status } = useRealtimeConnection()

const statusMessage = computed(() => {
  switch (status.value) {
    case 'connected': return 'Online'
    case 'disconnected': return 'Offline'
    case 'connecting': return 'Connecting...'
    case 'reconnecting': return 'Reconnecting...'
  }
})

attempt

A readonly ref with the current reconnection attempt number. undefined when not reconnecting:

const { status, attempt } = useRealtimeConnection()

// Only defined during reconnection
if (status.value === 'reconnecting') {
  console.log(`Reconnection attempt ${attempt.value}`)
}

connect()

Manually initiate a connection:

const { connect, disconnect } = useRealtimeConnection()

// Disconnect
disconnect()

// Later, reconnect
connect()

disconnect()

Manually disconnect from the server:

const { disconnect } = useRealtimeConnection()

function goOffline() {
  disconnect()
}

socket

Access the raw Socket.IO socket instance for advanced usage:

const { socket } = useRealtimeConnection()

// Listen to custom events
socket.on('custom-event', (data) => {
  console.log('Custom event:', data)
})

// Emit custom events
socket.emit('custom-event', { foo: 'bar' })
Direct socket access is an escape hatch. Prefer using useRealtimeState and useRealtimeEvents for most use cases.

Examples

Connection Status Badge

Show a visual indicator of the connection status:

ConnectionBadge.vue
<script setup>
const { connected, status, attempt } = useRealtimeConnection()

const statusConfig = computed(() => {
  switch (status.value) {
    case 'connected':
      return { color: 'success', icon: 'i-lucide-wifi', text: 'Connected' }
    case 'disconnected':
      return { color: 'error', icon: 'i-lucide-wifi-off', text: 'Disconnected' }
    case 'connecting':
      return { color: 'warning', icon: 'i-lucide-loader', text: 'Connecting' }
    case 'reconnecting':
      return { color: 'warning', icon: 'i-lucide-loader', text: `Reconnecting (${attempt.value})` }
  }
})
</script>

<template>
  <UBadge :color="statusConfig.color">
    <UIcon :name="statusConfig.icon" class="mr-1" />
    {{ statusConfig.text }}
  </UBadge>
</template>

Connection Events Logging

Log all connection events for debugging:

ConnectionLogger.vue
<script setup>
const logs = ref<string[]>([])

function log(message: string) {
  logs.value.unshift(`[${new Date().toLocaleTimeString()}] ${message}`)
}

const { status } = useRealtimeConnection({
  onConnected: () => log('Connected to server'),
  onDisconnected: (reason) => log(`Disconnected: ${reason}`),
  onReconnecting: (attempt) => log(`Reconnecting, attempt ${attempt}`),
  onReconnected: (attempt) => log(`Reconnected after ${attempt} attempts`),
  onReconnectFailed: () => log('Reconnection failed'),
  onError: (error) => log(`Error: ${error.message}`),
})
</script>

<template>
  <div>
    <h3>Connection Logs</h3>
    <ul>
      <li v-for="(entry, i) in logs" :key="i">{{ entry }}</li>
    </ul>
  </div>
</template>

Offline Banner

Show a banner when disconnected:

OfflineBanner.vue
<script setup>
const { connected, status } = useRealtimeConnection()
</script>

<template>
  <Transition name="slide">
    <div
      v-if="!connected"
      class="fixed top-0 inset-x-0 bg-yellow-500 text-white p-2 text-center"
    >
      <span v-if="status === 'reconnecting'">
        Reconnecting to server...
      </span>
      <span v-else>
        You are offline. Some features may not work.
      </span>
    </div>
  </Transition>
</template>

<style scoped>
.slide-enter-active,
.slide-leave-active {
  transition: transform 0.3s ease;
}
.slide-enter-from,
.slide-leave-to {
  transform: translateY(-100%);
}
</style>

Manual Connection Control

Let users manually control their connection:

ConnectionControl.vue
<script setup>
const { connected, connect, disconnect } = useRealtimeConnection()
</script>

<template>
  <div>
    <p>Status: {{ connected ? 'Online' : 'Offline' }}</p>
    <button
      v-if="connected"
      @click="disconnect"
      class="bg-red-500 text-white px-4 py-2 rounded"
    >
      Go Offline
    </button>
    <button
      v-else
      @click="connect"
      class="bg-green-500 text-white px-4 py-2 rounded"
    >
      Reconnect
    </button>
  </div>
</template>

Disable Features When Offline

Conditionally disable features based on connection status:

OnlineOnly.vue
<script setup>
const { connected } = useRealtimeConnection()
const counter = useRealtimeState('counter', 0)
</script>

<template>
  <div>
    <p>Counter: {{ counter }}</p>
    <button
      :disabled="!connected"
      :class="{ 'opacity-50 cursor-not-allowed': !connected }"
      @click="counter++"
    >
      Increment
    </button>
    <p v-if="!connected" class="text-sm text-gray-500">
      Connect to modify the counter
    </p>
  </div>
</template>

Disconnect Reasons

The onDisconnected callback receives a reason string. Common reasons include:

ReasonDescription
io server disconnectServer forcefully disconnected the client
io client disconnectClient called socket.disconnect()
ping timeoutServer didn't respond to ping within timeout
transport closeConnection was closed (network issue, server restart)
transport errorConnection encountered an error
useRealtimeConnection({
  onDisconnected: (reason) => {
    if (reason === 'io server disconnect') {
      // Server kicked us out, may need to re-authenticate
      console.log('Server disconnected us')
    } else if (reason === 'io client disconnect') {
      // We disconnected intentionally
      console.log('We disconnected')
    } else {
      // Network issue, will auto-reconnect
      console.log('Connection lost, reconnecting...')
    }
  },
})