<script setup lang="ts">
const { isConnected, isReconnecting, connectionRetries } = useConvexConnectionState()
</script>
<template>
<div v-if="isReconnecting" class="offline-banner">
Reconnecting... (attempt {{ connectionRetries }})
</div>
</template>
| Property | Type | Description |
|---|---|---|
state | Readonly<Ref<ConnectionState>> | Full connection state object |
isConnected | ComputedRef<boolean> | WebSocket currently connected |
hasEverConnected | ComputedRef<boolean> | Has successfully connected before |
connectionRetries | ComputedRef<number> | Number of retry attempts |
hasInflightRequests | ComputedRef<boolean> | Has pending requests |
isReconnecting | ComputedRef<boolean> | Was connected, now disconnected |
inflightMutations | ComputedRef<number> | Pending mutations count |
inflightActions | ComputedRef<number> | Pending actions count |
interface ConnectionState {
hasInflightRequests: boolean
isWebSocketConnected: boolean
timeOfOldestInflightRequest: Date | null
hasEverConnected: boolean
connectionCount: number
connectionRetries: number
inflightMutations: number
inflightActions: number
}
<script setup lang="ts">
const { isConnected, hasEverConnected } = useConvexConnectionState()
// Only show banner if we were connected before
const showOfflineBanner = computed(() =>
hasEverConnected.value && !isConnected.value
)
</script>
<template>
<Transition name="slide">
<div v-if="showOfflineBanner" class="offline-banner">
<span>You're offline. Changes will sync when reconnected.</span>
</div>
</Transition>
</template>
<style scoped>
.offline-banner {
position: fixed;
top: 0;
left: 0;
right: 0;
background: #f59e0b;
color: white;
padding: 0.5rem;
text-align: center;
z-index: 1000;
}
.slide-enter-active,
.slide-leave-active {
transition: transform 0.3s ease;
}
.slide-enter-from,
.slide-leave-to {
transform: translateY(-100%);
}
</style>
<script setup lang="ts">
const { isReconnecting, connectionRetries } = useConvexConnectionState()
</script>
<template>
<div v-if="isReconnecting" class="reconnecting">
<div class="spinner" />
<span>
Reconnecting
<span v-if="connectionRetries > 0">
(attempt {{ connectionRetries + 1 }})
</span>
</span>
</div>
</template>
<style scoped>
.reconnecting {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
background: #fef3c7;
border-radius: 0.375rem;
}
.spinner {
width: 1rem;
height: 1rem;
border: 2px solid #d97706;
border-top-color: transparent;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
<script setup lang="ts">
const { inflightMutations, inflightActions, hasInflightRequests } = useConvexConnectionState()
const pendingCount = computed(() =>
inflightMutations.value + inflightActions.value
)
</script>
<template>
<div v-if="hasInflightRequests" class="sync-indicator">
<div class="sync-spinner" />
<span>Syncing {{ pendingCount }} changes...</span>
</div>
</template>
<script setup lang="ts">
const { isConnected, isReconnecting, hasEverConnected } = useConvexConnectionState()
const statusColor = computed(() => {
if (!hasEverConnected.value) return 'gray'
if (isConnected.value) return 'green'
if (isReconnecting.value) return 'yellow'
return 'red'
})
const statusText = computed(() => {
if (!hasEverConnected.value) return 'Connecting...'
if (isConnected.value) return 'Connected'
if (isReconnecting.value) return 'Reconnecting...'
return 'Offline'
})
</script>
<template>
<header class="app-header">
<div class="logo">MyApp</div>
<div class="connection-status" :class="statusColor">
<span class="status-dot" />
{{ statusText }}
</div>
</header>
</template>
<style scoped>
.connection-status {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.875rem;
}
.status-dot {
width: 0.5rem;
height: 0.5rem;
border-radius: 50%;
}
.green .status-dot { background: #10b981; }
.yellow .status-dot { background: #f59e0b; animation: pulse 1s infinite; }
.red .status-dot { background: #ef4444; }
.gray .status-dot { background: #9ca3af; }
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
</style>
<script setup lang="ts">
const { inflightMutations, isConnected } = useConvexConnectionState()
const saveStatus = computed(() => {
if (!isConnected.value) return 'offline'
if (inflightMutations.value > 0) return 'saving'
return 'saved'
})
</script>
<template>
<div class="save-status">
<template v-if="saveStatus === 'saving'">
<div class="spinner-small" />
Saving...
</template>
<template v-else-if="saveStatus === 'saved'">
<span class="check">✓</span>
Saved
</template>
<template v-else>
<span class="warning">⚠</span>
Offline
</template>
</div>
</template>
For advanced use cases, access the complete state object:
<script setup lang="ts">
const { state } = useConvexConnectionState()
// Debug: log all state changes
watch(state, (newState) => {
console.log('Connection state:', {
connected: newState.isWebSocketConnected,
retries: newState.connectionRetries,
pendingMutations: newState.inflightMutations,
pendingActions: newState.inflightActions,
oldestRequest: newState.timeOfOldestInflightRequest,
})
})
</script>
logging.enabled in your Nuxt config to automatically log all connection:change events without manual watchers.