Loading states show users that something is happening in the background. This helps avoid confusion when data or content takes time to appear.
Loading states pattern in Vue
<template>
<div>
<div v-if="isLoading">Loading...</div>
<div v-else>Content is ready!</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const isLoading = ref(true)
// Simulate loading
setTimeout(() => {
isLoading.value = false
}, 2000)
</script>Use v-if to show or hide loading messages or spinners.
Use a reactive variable like isLoading to track loading state.
<template>
<div>
<div v-if="loading">Please wait...</div>
<div v-else>Data loaded!</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const loading = ref(true)
setTimeout(() => loading.value = false, 1000)
</script><template>
<div>
<button @click="loadData" :disabled="loading">
{{ loading ? 'Loading...' : 'Load Data' }}
</button>
<div v-if="data">{{ data }}</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const loading = ref(false)
const data = ref(null)
function loadData() {
loading.value = true
setTimeout(() => {
data.value = 'Here is your data!'
loading.value = false
}, 1500)
}
</script>This Vue component shows a button to fetch content. When clicked, it shows a loading message for 3 seconds. The button disables during loading to prevent repeated clicks. The loading message uses ARIA roles for accessibility.
<template>
<main>
<h1>Loading States Example</h1>
<section aria-live="polite">
<div v-if="loading" role="status" aria-label="Loading content">
<p>Loading content, please wait...</p>
</div>
<div v-else>
<p>Content loaded successfully!</p>
</div>
</section>
<button @click="fetchContent" :disabled="loading" :aria-busy="loading">
{{ loading ? 'Loading...' : 'Fetch Content' }}
</button>
</main>
</template>
<script setup>
import { ref } from 'vue'
const loading = ref(false)
function fetchContent() {
loading.value = true
setTimeout(() => {
loading.value = false
}, 3000)
}
</script>
<style scoped>
main {
max-width: 30rem;
margin: 2rem auto;
font-family: system-ui, sans-serif;
padding: 1rem;
border: 1px solid #ccc;
border-radius: 0.5rem;
text-align: center;
}
button {
margin-top: 1rem;
padding: 0.5rem 1rem;
font-size: 1rem;
cursor: pointer;
border: 2px solid #007acc;
border-radius: 0.3rem;
background-color: white;
color: #007acc;
transition: background-color 0.3s ease;
}
button:disabled {
cursor: not-allowed;
opacity: 0.6;
}
button:not(:disabled):hover {
background-color: #007acc;
color: white;
}
</style>Always provide clear feedback so users know the app is working.
Use ARIA roles like role="status" and aria-live="polite" to help screen readers announce loading changes.
Disable buttons or inputs during loading to avoid duplicate actions.
Loading states improve user experience by showing progress.
Use reactive variables and v-if to toggle loading messages.
Accessibility and disabling controls during loading are important.
Practice
Solution
Step 1: Understand user experience during data fetching
Loading states inform users that the app is working on a task, preventing confusion.Step 2: Identify the purpose of loading states in Vue
They show progress or waiting messages while data loads or actions complete.Final Answer:
To show users that data is being fetched or processed -> Option BQuick Check:
Loading states = user feedback [OK]
- Thinking loading states hide content permanently
- Confusing loading states with disabling reactivity
- Assuming loading states change component size
isLoading is true?Solution
Step 1: Understand
v-ifusagev-ifconditionally renders the element only if the expression is true.Step 2: Match condition to show loading
We want to show the message whenisLoadingis true, sov-if="isLoading"is correct.Final Answer:
<div v-if="isLoading">Loading...</div> -> Option CQuick Check:
Show loading if isLoading true = v-if="isLoading" [OK]
- Using v-if with negation (!isLoading) to show loading
- Using v-show which toggles visibility but keeps element
- Using invalid v-bind syntax for conditional rendering
const isLoading = ref(true);
setTimeout(() => { isLoading.value = false; }, 2000);
What will the component show initially if template has <div v-if="isLoading">Loading...</div><div v-else>Content Loaded</div>?Solution
Step 1: Analyze initial value of
It starts asisLoadingtrue, sov-if="isLoading"shows "Loading..." initially.Step 2: Understand the timeout effect
After 2 seconds,isLoading.valuebecomesfalse, switching tov-elsecontent "Content Loaded".Final Answer:
Loading... for 2 seconds, then Content Loaded -> Option AQuick Check:
Initial true shows loading, then false shows content [OK]
- Assuming content shows immediately ignoring initial true
- Thinking loading never stops without reactivity knowledge
- Confusing v-if and v-else rendering timing
const isLoading = ref(false);
function fetchData() {
isLoading = true;
fetch('/api/data')
.then(() => { isLoading = false; });
}Solution
Step 1: Understand how to update Vue refs
Refs are objects; their value must be changed via.value, not by direct assignment.Step 2: Identify incorrect assignments
Code assignsisLoading = trueinstead ofisLoading.value = true, causing errors.Final Answer:
Directly assigning to ref variable instead of its .value -> Option DQuick Check:
Update ref with .value, not direct assignment [OK]
- Assigning ref variable directly instead of .value
- Forgetting to handle promise with then or async/await
- Assuming fetch syntax is wrong when it is correct
isLoading reactive variable?Solution
Step 1: Disable button based on loading state
Use:disabled="isLoading"to disable the button when loading.Step 2: Show dynamic button text
Use interpolation with a ternary to show "Loading..." or "Submit" based onisLoading.Final Answer:
<button :disabled="isLoading">{{ isLoading ? 'Loading...' : 'Submit' }}</button> -> Option AQuick Check:
Disable button and show loading text with :disabled and ternary [OK]
- Using v-if to swap buttons instead of disabling
- Negating isLoading for disabling logic
- Using non-existent :loading attribute on button
Ready to prove it?
Pass the test and this pattern moves unknown
