Chapter 76: Vue v-else-if Directive
V-else-if
This directive is only meaningful when it comes right after a v-if (or another v-else-if), and it lets you create clean, chained conditional blocks without nesting a bunch of v-ifs inside each other or creating unnecessary extra elements.
It is exactly what you would write in JavaScript as else if (…) { … }.
1. The Basic Pattern – How v-if / v-else-if / v-else Work Together
|
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
<template> <div class="status-box"> <!-- First condition --> <div v-if="status === 'success'" class="success"> Operation completed successfully! </div> <!-- Second condition – only checked if first is false --> <div v-else-if="status === 'error'" class="error"> Something went wrong: {{ errorMessage }} </div> <!-- Third condition – only checked if previous are false --> <div v-else-if="status === 'loading'" class="loading"> <div class="spinner"></div> Loading, please wait... </div> <!-- Fallback – when nothing above matched --> <div v-else class="unknown"> Unknown status </div> </div> </template> <script setup lang="ts"> import { ref } from 'vue' const status = ref<'success' | 'error' | 'loading' | 'pending'>('loading') const errorMessage = ref('Network timeout') // Simulate changing status setTimeout(() => { status.value = 'success' }, 2000) </script> <style scoped> .status-box { padding: 2rem; border-radius: 12px; margin: 2rem auto; max-width: 500px; text-align: center; } .success { background: #dcfce7; color: #166534; padding: 1.5rem; border-radius: 8px; } .error { background: #fee2e2; color: #991b1b; padding: 1.5rem; border-radius: 8px; } .loading { background: #f3f4f6; color: #4b5563; padding: 1.5rem; border-radius: 8px; } .unknown { background: #fef3c7; color: #92400e; padding: 1.5rem; border-radius: 8px; } .spinner { width: 40px; height: 40px; border: 4px solid #f3f3f3; border-top: 4px solid #3b82f6; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 1rem; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } </style> |
2. The Golden Rules of v-else-if (Memorize These)
-
Must come immediately after v-if or another v-else-if → You cannot have anything between them (no text, no other element)
Wrong:
HTML012345678<div v-if="a">A</div><p>Some text</p> <!-- ← breaks the chain --><div v-else-if="b">B</div>Correct:
HTML01234567<div v-if="a">A</div><div v-else-if="b">B</div> -
You can chain as many v-else-if as you want
-
v-else (no condition) must be the very last in the chain
-
All of them can be used on <template> tags (to group multiple elements without extra wrapper)
vue01234567891011121314151617<template v-if="user.role === 'admin'"><h1>Admin Dashboard</h1><button>Delete User</button></template><template v-else-if="user.role === 'editor'"><h1>Editor Panel</h1><button>Edit Post</button></template><template v-else><h1>Guest View</h1><p>Please log in</p></template>→ No extra <div> cluttering your DOM
3. Real-World Example – Payment Status Card
|
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
<template> <div class="payment-card"> <h2>Payment Status</h2> <div v-if="payment.status === 'success'" class="status success"> <div class="icon">✔</div> <p>Payment completed successfully!</p> <p class="amount">Amount: ₹{{ payment.amount.toLocaleString() }}</p> <p class="date">Date: {{ payment.date }}</p> </div> <div v-else-if="payment.status === 'pending'" class="status pending"> <div class="icon">⏳</div> <p>Payment is being processed...</p> <p class="amount">Amount: ₹{{ payment.amount.toLocaleString() }}</p> <button @click="retryPayment">Retry Payment</button> </div> <div v-else-if="payment.status === 'failed'" class="status failed"> <div class="icon">✖</div> <p>Payment failed</p> <p class="reason">Reason: {{ payment.reason }}</p> <p class="amount">Amount: ₹{{ payment.amount.toLocaleString() }}</p> <button @click="retryPayment">Try Again</button> </div> <div v-else class="status unknown"> <div class="icon">?</div> <p>Unknown payment status</p> <button @click="checkStatus">Check Status</button> </div> </div> </template> <script setup lang="ts"> import { reactive } from 'vue' const payment = reactive({ status: 'pending', amount: 4999, date: '2026-02-21', reason: 'Insufficient funds' }) function retryPayment() { payment.status = 'pending' // fake retry setTimeout(() => { payment.status = Math.random() > 0.5 ? 'success' : 'failed' }, 1500) } function checkStatus() { alert('Status check not implemented') } </script> <style scoped> .payment-card { max-width: 500px; margin: 3rem auto; padding: 2rem; background: white; border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); text-align: center; } .status { padding: 2rem; border-radius: 12px; margin-top: 1.5rem; } .success { background: #dcfce7; color: #166534; } .pending { background: #fef3c7; color: #92400e; } .failed { background: #fee2e2; color: #991b1b; } .unknown { background: #f3f4f6; color: #4b5563; } .icon { font-size: 4rem; margin-bottom: 1rem; } .amount { font-size: 1.5rem; font-weight: bold; margin: 1rem 0; } button { padding: 0.8rem 1.5rem; background: #3b82f6; color: white; border: none; border-radius: 6px; cursor: pointer; margin-top: 1rem; } </style> |
Quick Summary Table – v-if Family (2026 Must-Know)
| Directive | When to use it | DOM presence when false | Re-mounts on true? | Cost on toggle | Animation support |
|---|---|---|---|---|---|
| v-if | Condition changes rarely, heavy content | Removed | Yes | Higher | Perfect with <Transition> |
| v-else-if | Chain of conditions | Removed | Yes | Higher | Yes |
| v-else | Default fallback | Removed | Yes | Higher | Yes |
| v-show | Condition changes frequently, light content | Hidden (display:none) | No | Very low | Works, but element always exists |
Pro Tips from Real Projects (Hyderabad 2026)
- Use v-if / v-else-if chains for status indicators, auth states, form steps, payment results
- Use <template v-if> when you want to conditionally render multiple elements without extra wrapper div
- Prefer v-show for very frequent toggles (tabs, accordions, loading spinners)
- Combine v-if + <Transition> for beautiful enter/leave animations
- Never put very expensive components behind v-else-if if the condition changes often — use v-show instead
- For accessibility → make sure screen readers understand the conditional content (use aria-live when needed)
Your mini practice task:
- Create a payment status component with v-if / v-else-if / v-else chain
- Add different icons, colors, buttons for each state
- Add a button to simulate changing status
- Wrap with <Transition name=”fade”> → see smooth state changes
Any part confusing? Want full examples for:
- v-if + <Transition> + modal animation?
- v-if vs v-show performance comparison?
- v-if inside <TransitionGroup> for list items?
- Real auth guard with v-if + router?
Just tell me — we’ll build the next clean conditional UI together 🚀
