SSR hydration state detection for components that need to behave differently during SSR vs client-side rendering.
Features
- Hydration state detection (browser vs SSR)
- Root component detection
- Readonly hydration state refs
- Plugin installation support
- Settled state tracking (after nextTick post-hydration)
Installation
import { createHydrationPlugin } from '@vuetify/v0'
const app = createApp(App)
app.use(createHydrationPlugin())
Basic Usage
<script setup lang="ts">
import { useHydration } from '@vuetify/v0'
const hydration = useHydration()
const showContent = computed(() =>
hydration.isHydrated.value
)
</script>
<template>
<div>
<p v-if="!showContent">Loading...</p>
<p v-else>Content is hydrated!</p>
</div>
</template>
API Reference
createHydration()
Creates a hydration instance.
Returns: HydrationContext
HydrationContext
isHydrated
Readonly<ShallowRef<boolean>>
True when root component has mounted (hydration complete)Initially false during SSR and before first mount.
Set to true when the root component mounts.
isSettled
Readonly<ShallowRef<boolean>>
True after first tick post-hydrationSafe for animations and transitions after state restoration.
Set to true after nextTick() following hydration.
Mark hydration as completeAutomatically called by the plugin when root component mounts.
Rarely needed to call manually.
Mark as settledAutomatically called after nextTick() post-hydration.
Rarely needed to call manually.
Use Cases
Conditional Client-Only Rendering
<script setup lang="ts">
import { useHydration } from '@vuetify/v0'
const hydration = useHydration()
</script>
<template>
<div>
<!-- Always rendered -->
<p>Server and client content</p>
<!-- Only rendered after hydration -->
<ClientOnly v-if="hydration.isHydrated.value">
<InteractiveComponent />
</ClientOnly>
</div>
</template>
Animation After Hydration
<script setup lang="ts">
import { useHydration } from '@vuetify/v0'
import { watch } from 'vue'
const hydration = useHydration()
watch(() => hydration.isSettled.value, (settled) => {
if (settled) {
// Safe to start animations now
startAnimations()
}
})
</script>
Conditional Logic Based on Hydration
import { useHydration } from '@vuetify/v0'
const hydration = useHydration()
if (hydration.isHydrated.value) {
// Client-side only logic
setupClientFeatures()
} else {
// SSR or pre-hydration logic
setupSSRFeatures()
}
Integration with Other Composables
With useBreakpoints
<script setup lang="ts">
import { useHydration, useBreakpoints } from '@vuetify/v0'
import { watch } from 'vue'
const hydration = useHydration()
const breakpoints = useBreakpoints()
watch(() => hydration.isHydrated.value, (hydrated) => {
if (hydrated) {
// Breakpoints are now reliable
console.log('Current breakpoint:', breakpoints.name.value)
}
})
</script>
With Client-Only Components
<script setup lang="ts">
import { useHydration } from '@vuetify/v0'
import { defineAsyncComponent } from 'vue'
const hydration = useHydration()
const HeavyComponent = defineAsyncComponent(() =>
import('./HeavyComponent.vue')
)
</script>
<template>
<div>
<component
v-if="hydration.isSettled.value"
:is="HeavyComponent"
/>
</div>
</template>
SSR Safety
The composable is SSR-safe and will work correctly in both server and client environments:
import { useHydration } from '@vuetify/v0'
// During SSR
const hydration = useHydration()
console.log(hydration.isHydrated.value) // false
console.log(hydration.isSettled.value) // false
// After hydration on client
console.log(hydration.isHydrated.value) // true
console.log(hydration.isSettled.value) // true (after nextTick)
Advanced Usage
Custom Hydration Context
import { createHydrationContext } from '@vuetify/v0'
const [useAppHydration, provideAppHydration] = createHydrationContext({
namespace: 'app:hydration',
})
// In root component
provideAppHydration()
// In child components
const hydration = useAppHydration()
Manual Control
import { createHydration } from '@vuetify/v0'
const hydration = createHydration()
// Manually mark as hydrated
hydration.hydrate()
// Manually mark as settled
hydration.settle()