Connection state
Present offline, reconnecting, and pending-operation state without confusing it with backend health.
useConvexConnectionState() observes the current primary Convex client's connection state. It returns UseConvexConnectionStateReturn; every field is a computed ref.
const { state, isConnected, isReconnecting, pendingMutations, pendingActions } =
useConvexConnectionState()Offline banner
<script setup lang="ts">
const { isConnected, isReconnecting } = useConvexConnectionState()
// This delay is a product choice, so it lives in the application.
const showOfflineBanner = ref(false)
let timer: ReturnType<typeof setTimeout> | undefined
let stopWatching: (() => void) | undefined
onMounted(() => {
stopWatching = watch(
isConnected,
(connected) => {
clearTimeout(timer)
if (connected) {
showOfflineBanner.value = false
return
}
timer = setTimeout(() => {
showOfflineBanner.value = true
}, 500)
},
{ immediate: true },
)
})
onBeforeUnmount(() => {
stopWatching?.()
clearTimeout(timer)
})
</script>
<template>
<aside v-if="showOfflineBanner" role="status">
{{ isReconnecting ? 'Reconnecting to live updates…' : 'Live updates are offline.' }}
</aside>
</template>The composable reports transport facts immediately. During server rendering, and in a Nuxt build without a Convex URL, it reports the disconnected state that the browser runtime starts from, so the first browser render matches the server HTML. The example delays its banner until after mount so the application, not the library, decides when to show it.
What connection means
isConnected reports the WebSocket connection. It does not prove:
- every backend dependency is healthy;
- a pending mutation committed;
- the browser has general internet access;
- a third-party API called by an action is available.
Use operation results and product queries for those facts.
Pending operations
pendingMutations and pendingActions come from the Convex connection state. They support a general “saving” indicator, not per-form attribution.
Identity changes
When the runtime replaces the primary client, connection state resets to the disconnected snapshot and observation rebinds to the replacement. Do not preserve the old client's connected badge through the transition.
Cleanup
Mounted consumers share one underlying connection-state subscription. The runtime subscribes for the first consumer and removes it after the last scope ends.
In the browser, calling the composable outside a component or Vue effect scope throws immediately. A connection subscription must stop when its scope ends. Utility code should receive the connection state from its caller, or run inside an effect scope that it creates.