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>
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>
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>
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>