← All context files

vuetify3/feedback.md

Vuetify 3 – Feedback (Dialog, Snackbar, Alert)

v-dialog

<template>
  <v-btn @click="open = true">Edit user</v-btn>

  <v-dialog v-model="open" max-width="500" persistent>
    <v-card>
      <v-card-title>Edit user</v-card-title>
      <v-card-text>
        <v-text-field v-model="form.name" label="Name" />
        <v-text-field v-model="form.email" label="Email" />
      </v-card-text>
      <v-card-actions>
        <v-spacer />
        <v-btn variant="text" @click="open = false">Cancel</v-btn>
        <v-btn color="primary" @click="save">Save</v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>

Confirm-style dialog as a reusable component

<!-- ConfirmDialog.vue -->
<template>
  <v-dialog v-model="show" max-width="420" persistent>
    <v-card>
      <v-card-title>{{ title }}</v-card-title>
      <v-card-text>{{ message }}</v-card-text>
      <v-card-actions>
        <v-spacer />
        <v-btn variant="text" @click="answer(false)">Cancel</v-btn>
        <v-btn color="primary" @click="answer(true)">Confirm</v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>

<script>
export default {
  data() {
    return { show: false, title: '', message: '', resolve: null }
  },
  methods: {
    open({ title, message }) {
      this.title = title
      this.message = message
      this.show = true
      return new Promise((resolve) => { this.resolve = resolve })
    },
    answer(value) {
      this.show = false
      this.resolve(value)
    },
  },
}
</script>

Used like:

async deleteUser(user) {
  const ok = await this.$refs.confirm.open({
    title: 'Delete user',
    message: `Delete ${user.name}? This cannot be undone.`,
  })
  if (ok) await api.delete(`/users/${user.id}`)
}

v-snackbar

For transient feedback ("Saved", "Error", etc.).

<template>
  <v-snackbar v-model="snack.show" :color="snack.color" :timeout="3000">
    {{ snack.text }}
    <template #actions>
      <v-btn variant="text" @click="snack.show = false">Close</v-btn>
    </template>
  </v-snackbar>
</template>

<script>
export default {
  data() {
    return { snack: { show: false, text: '', color: 'success' } }
  },
  methods: {
    notify(text, color = 'success') {
      this.snack = { show: true, text, color }
    },
  },
}
</script>

A common pattern is to put this snackbar in App.vue and trigger it from a Pinia store (useNotifyStore) so any component can call notify.show('Saved').

v-alert

For inline, non-transient messages (validation summaries, banner warnings).

<v-alert type="error" variant="tonal" closable>
  Could not save changes — server returned 500.
</v-alert>

<v-alert type="info" variant="outlined" title="Heads up" text="Your session expires in 5 minutes." />

type (sets icon + color): success, info, warning, error. variant: flat, elevated, tonal (lighter background), outlined, text.

v-progress-linear / v-progress-circular

<!-- indeterminate -->
<v-progress-linear indeterminate color="primary" />

<!-- value-driven -->
<v-progress-linear :model-value="uploadPct" color="success" height="8" />

<!-- circular -->
<v-progress-circular indeterminate :size="48" color="primary" />

Pair with :loading="loading" on <v-btn> for "saving…" states:

<v-btn color="primary" :loading="saving" @click="save">Save</v-btn>