Chapter 6: Vue v-show
Vue v-show is Vue’s CSS-based conditional visibility tool. It decides whether an element is visible or hidden by toggling the display CSS property (usually between display: none and the element’s natural display value like block, flex, inline, etc.).
Key sentence from the official Vue 3 docs (vuejs.org):
v-show works by setting the display CSS property via inline styles, and will try to respect the initial display value when the element is visible. It also triggers transitions when its condition changes.
In simple words:
- Condition = true → element is visible (normal display)
- Condition = false → element gets style=”display: none;” (hidden but still in the DOM)
Unlike v-if, the element is always rendered and never destroyed — only hidden/shown.
1. Basic Hello World Example with v-show
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<template> <div class="demo-box"> <button @click="isVisible = !isVisible"> {{ isVisible ? 'Hide' : 'Show' }} Message </button> <p v-show="isVisible" class="highlight"> Hello from Hyderabad! 🌶️ You can see me now. </p> <small>(Check devtools → Elements tab — I'm always here!)</small> </div> </template> <script setup> import { ref } from 'vue' const isVisible = ref(true) </script> <style scoped> .demo-box { padding: 1.5rem; text-align: center; } .highlight { font-size: 1.4rem; padding: 1rem; background: #fef3c7; border-radius: 8px; margin-top: 1rem; } </style> |
→ Click the button many times → text appears/disappears instantly → Open browser devtools (F12) → Elements → search for the <p> → it’s always present, just gets display: none when hidden.
2. How v-show Actually Works Under the Hood
When Vue sees v-show=”someCondition”:
- It renders the element normally first time (even if condition is false initially)
- It adds/removes an inline style: display: none !important; (or removes it)
- It remembers the original display value (from CSS or default) so when shown again → correct display: flex / block / etc. is restored
- It plays nicely with <Transition> / <TransitionGroup> (enter/leave animations work)
No DOM nodes are created/destroyed → very fast toggling.
3. v-show vs v-if – The Classic Comparison (interview favorite!)
| Feature | v-show | v-if |
|---|---|---|
| DOM presence when false | Stays in DOM (just display: none) | Completely removed from DOM |
| Initial render (condition false) | Slower – renders everything | Faster – nothing rendered at all |
| Toggling performance | Extremely cheap (just CSS change) | Expensive (mount/unmount components, re-run setup, etc.) |
| Best for | Frequent toggles (tabs, accordions, tooltips, loading spinners) | Rare/infrequent conditions (modals, auth gates, heavy sections) |
| Works with <template> | No (doesn’t support it) | Yes (invisible wrapper) |
| Works with v-else / v-else-if | No | Yes |
| Component lifecycle | Always mounted once (mounted/unmounted never fire again) | Fires mounted/unmounted every toggle |
| Memory/CPU when hidden | Higher (element + reactivity watchers exist) | Lower (nothing exists) |
| Transition/animation support | Excellent (CSS transitions) | Excellent (but with enter/leave hooks) |
2026 real-world rule-of-thumb from senior devs:
- Use v-show when the thing toggles often (daily 10–100+ times) → e.g. dark mode toggle, tab content, mobile menu, password visibility eye icon, form error messages
- Use v-if when the thing is rarely shown or heavy/expensive → e.g. full-screen modal, admin panel, large chart library, user-uploaded content that needs cleanup
Pro trick people use in 2026 for heavy components that toggle often:
|
0 1 2 3 4 5 6 7 8 9 |
<ExpensiveChart v-if="activeTab === 'chart'" v-show="activeTab === 'chart'" /> |
→ v-if ensures it only renders the first time tab is selected → v-show prevents destroy/re-create on every tab switch after that → best of both worlds!
4. Real Example – Password Visibility Toggle (classic v-show use-case)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<template> <div class="form-group"> <label for="password">Password</label> <div class="input-wrapper"> <input :type="showPassword ? 'text' : 'password'" id="password" v-model="password" /> <button type="button" class="eye-btn" @click="showPassword = !showPassword" aria-label="Toggle password visibility" > {{ showPassword ? '🙈' : '👁️' }} </button> </div> <small v-show="password.length > 0 && password.length < 6" class="error"> Password must be at least 6 characters </small> </div> </template> <script setup> import { ref } from 'vue' const password = ref('') const showPassword = ref(false) </script> <style scoped> .input-wrapper { position: relative; } .eye-btn { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); background: none; border: none; cursor: pointer; font-size: 1.2rem; } .error { color: #dc2626; display: block; margin-top: 0.3rem; } </style> |
→ Error message uses v-show → toggles very frequently as user types → perfect choice (If we used v-if here → unnecessary re-renders on every keystroke)
5. Important Limitations of v-show
- No <template v-show> — won’t work (use <div> or real element)
- No v-else / v-else-if support
- Hidden elements still consume resources (event listeners, watchers, computed, child components stay alive)
- If you hide something very heavy (like a map or video player) → consider v-if + KeepAlive instead
Summary – Quick Decision Table
| Scenario | Recommended | Why? |
|---|---|---|
| Tab content switching 50× a day | v-show | Fast toggles |
| Form validation messages | v-show | Frequent changes |
| Mobile hamburger menu | v-show | Quick open/close |
| Full admin dashboard (only for admins) | v-if | Security + perf |
| Large modal with forms/charts | v-if | Don’t keep it alive |
| Loading spinner during fetch | v-show | Flickers often |
Practice this: Take your todo app from earlier lessons → add v-show to:
- “No todos yet” message
- Loading state
- Error banner
Toggle them frequently and compare feel vs using v-if.
Any confusion? Want example with <Transition> + v-show? Or how to combine with v-if for heavy tabs? Or real Pinia + v-show auth check?
Just tell me — we’ll keep building your Vue intuition step by step 🚀
Keep shining from Hyderabad! 💙
