Getting Started

Usage

Quick overview of the Nuxt Realtime composables.

Nuxt Realtime provides three main composables for building real-time applications. This page gives a quick overview - see the individual composable pages for full API documentation.

useRealtimeState

Share reactive state across all connected clients. Works just like Vue's useState but syncs automatically.

<script setup>
const counter = useRealtimeState('counter', 0)
</script>

<template>
  <button @click="counter++">Count: {{ counter }}</button>
</template>
See the full useRealtimeState documentation for options, return values, and more examples.

useRealtimeEvents

Publish and subscribe to events across clients. Perfect for notifications, chat messages, or any ephemeral real-time communication.

<script setup>
const { subscribe, publish } = useRealtimeEvents()

subscribe('notifications', (data) => {
  console.log('Received:', data)
})

function notify() {
  publish('notifications', { message: 'Hello!' })
}
</script>
See the full useRealtimeEvents documentation for subscribe options, typing, and more examples.

useRealtimeConnection

Monitor and control the WebSocket connection status.

<script setup>
const { connected, status, attempt } = useRealtimeConnection({
  onConnected: () => console.log('Connected'),
  onDisconnected: (reason) => console.log('Disconnected:', reason),
})
</script>

<template>
  <span :class="connected ? 'text-green-500' : 'text-red-500'">
    {{ status }}
  </span>
</template>
See the full useRealtimeConnection documentation for all callbacks and manual control methods.

Putting It All Together

Here's a complete example combining all three composables:

app.vue
<script setup>
// Shared state
const messages = useRealtimeState('chat-messages', [])

// Connection status
const { connected, status } = useRealtimeConnection({
  onReconnected: () => {
    // Refresh messages after reconnection
    messages.refresh()
  },
})

// Events for typing indicators
const { subscribe, publish } = useRealtimeEvents()
const typingUsers = ref(new Set())

subscribe('typing', ({ userId, isTyping }) => {
  if (isTyping) {
    typingUsers.value.add(userId)
  } else {
    typingUsers.value.delete(userId)
  }
})

const input = ref('')
const userId = crypto.randomUUID()

function sendMessage() {
  if (!input.value.trim()) return

  messages.value = [
    ...messages.value,
    { userId, text: input.value, timestamp: Date.now() },
  ]
  input.value = ''
}

function onTyping() {
  publish('typing', { userId, isTyping: true })
}
</script>

<template>
  <div>
    <!-- Connection status -->
    <div class="mb-4">
      Status: <span :class="connected ? 'text-green-500' : 'text-red-500'">{{ status }}</span>
    </div>

    <!-- Messages -->
    <div class="space-y-2 mb-4">
      <div v-for="msg in messages" :key="msg.timestamp">
        <strong>{{ msg.userId.slice(0, 8) }}:</strong> {{ msg.text }}
      </div>
    </div>

    <!-- Typing indicator -->
    <p v-if="typingUsers.size > 0" class="text-sm text-gray-500">
      {{ typingUsers.size }} user(s) typing...
    </p>

    <!-- Input -->
    <form @submit.prevent="sendMessage" class="flex gap-2">
      <input
        v-model="input"
        :disabled="!connected"
        placeholder="Type a message..."
        class="flex-1 border rounded px-3 py-2"
        @input="onTyping"
      />
      <button
        type="submit"
        :disabled="!connected"
        class="bg-primary-500 text-white px-4 py-2 rounded"
      >
        Send
      </button>
    </form>
  </div>
</template>