0
0
Vueframework~5 mins

Loading states pattern in Vue

Choose your learning style9 modes available
Introduction

Loading states show users that something is happening in the background. This helps avoid confusion when data or content takes time to appear.

When fetching data from a server and waiting for the response.
When submitting a form and waiting for confirmation.
When loading images or files that take time to appear.
When switching between pages or views that need to load content.
Syntax
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.

Examples
Simple loading message that changes after 1 second.
Vue
<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>
Button shows loading text and disables while data loads.
Vue
<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>
Sample Program

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.

Vue
<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>
OutputSuccess
Important Notes

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.

Summary

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.