Vue.js KeepAlive
KeepAlive is a built-in component that remembers other components instead of destroying them. Vue normally throws away a component when it leaves the page, and every visit rebuilds it from scratch. A form loses typed text, a scroll position jumps back to the top, and a counter returns to zero. KeepAlive stores the component in memory so the user finds everything exactly as left.
Think of a video game. Quitting a game and starting again returns you to the first level. Pausing the game keeps your progress. KeepAlive is the pause button for components.
The Problem with Switching Components
Tab interfaces built with dynamic components show the issue clearly. A user types a search term on one tab, visits another tab, and returns to find an empty box.
Diagram: State Without KeepAlive
Tab A: user types "laptop" Switch to Tab B --> Tab A destroyed Switch to Tab A --> new Tab A created, box is empty
Wrap Components with KeepAlive
Place <KeepAlive> around the dynamic component. Vue caches each component instance after the first visit.
<script setup>
import { shallowRef } from "vue";
import SearchTab from "./SearchTab.vue";
import HelpTab from "./HelpTab.vue";
const current = shallowRef(SearchTab);
</script>
<template>
<button @click="current = SearchTab">Search</button>
<button @click="current = HelpTab">Help</button>
<KeepAlive>
<component :is="current" />
</KeepAlive>
</template>Diagram: State With KeepAlive
Tab A: user types "laptop" Switch to Tab B --> Tab A hidden and stored in the cache Switch to Tab A --> same Tab A returns, box still says "laptop"
Choose What to Cache
The include and exclude props filter components by name. Names come from the component's name option or, in single file components, from the file name.
<!-- Cache only these two -->
<KeepAlive include="SearchTab,CartTab">
<component :is="current" />
</KeepAlive>
<!-- Cache everything except one -->
<KeepAlive exclude="LoginTab">
<component :is="current" />
</KeepAlive>A login form is a good exclusion because stale credentials in a cached form create a privacy concern.
Limit Memory with max
Every cached component uses memory. The max prop sets the number of instances Vue keeps. Once the limit is reached, Vue discards the least recently visited component.
<KeepAlive :max="3">
<component :is="current" />
</KeepAlive>Diagram: Least Recently Used Removal
max = 3 Visit A, B, C --> cache: [A, B, C] Visit D --> A is oldest, so cache: [B, C, D]
Lifecycle Hooks for Cached Components
A cached component never unmounts when hidden, so onMounted and onUnmounted run only once. Two special hooks fire on every show and hide.
<script setup>
import { onActivated, onDeactivated } from "vue";
onActivated(() => {
console.log("Tab is visible. Refresh the data here.");
});
onDeactivated(() => {
console.log("Tab is hidden. Pause timers here.");
});
</script>Diagram: Hook Order
First visit: created --> mounted --> activated Hide tab: deactivated Show again: activated (no new mounted) Removed from cache: unmounted
Use onActivated to refresh live data such as stock prices, and onDeactivated to pause timers or video playback.
KeepAlive with Router Views
Page-level caching works with Vue Router through the slot of RouterView.
<RouterView v-slot="{ Component }">
<KeepAlive>
<component :is="Component" />
</KeepAlive>
</RouterView>A visitor who scrolls a long product list, opens one product, and presses the back button lands at the same scroll position.
When to Skip KeepAlive
- Pages with sensitive data that should reset on every visit
- Components that must reload fresh data each time
- Applications with many large pages, since the cache consumes memory
Summary
KeepAlive preserves component state when a component leaves the screen. Wrap a dynamic component or router view, filter the cache with include and exclude, and cap memory with max. The onActivated and onDeactivated hooks react to every show and hide. Typed text, scroll positions, and counters survive navigation.
