Form Examples

Common patterns for using toasts with form validation and submission.

Basic Form Submission

Successful Submission

vue
<script setup>
const toast = useToast();
const form = ref({
  name: "",
  email: "",
});

async function handleSubmit() {
  try {
    await api.submitForm(form.value);

    toast.success(
      "Form Submitted",
      "Your information has been saved successfully"
    );

    // Reset form
    form.value = { name: "", email: "" };
  } catch (error) {
    toast.error("Submission Failed", error.message);
  }
}
</script>

<template>
  <form @submit.prevent="handleSubmit">
    <input v-model="form.name" placeholder="Name" />
    <input v-model="form.email" placeholder="Email" />
    <button type="submit">Submit</button>
  </form>
</template>

Validation Errors

vue
<script setup>
const toast = useToast();

function validateForm(form) {
  const errors = [];

  if (!form.email.includes("@")) {
    errors.push("Invalid email address");
  }

  if (form.password.length < 8) {
    errors.push("Password must be at least 8 characters");
  }

  if (errors.length > 0) {
    toast.error("Validation Error", errors.join(". "));
    return false;
  }

  return true;
}

async function handleSubmit() {
  if (!validateForm(form.value)) {
    return;
  }

  // Submit form...
}
</script>

File Upload Forms

Upload Progress

vue
<script setup>
const toast = useToast();

async function uploadFile(file) {
  // Show initial upload toast
  toast.info("Uploading...", file.name, {
    showProgress: true,
    duration: 10000,
  });

  try {
    await api.upload(file, {
      onProgress: (percent) => {
        // Update progress if needed
      },
    });

    toast.success("Upload Complete", `${file.name} uploaded successfully`);
  } catch (error) {
    toast.error("Upload Failed", error.message);
  }
}

function handleFileChange(event) {
  const files = Array.from(event.target.files);
  files.forEach(uploadFile);
}
</script>

<template>
  <input type="file" @change="handleFileChange" multiple />
</template>

Multiple File Upload

vue
<script setup>
const toast = useToast();

async function uploadMultipleFiles(files) {
  const fileArray = Array.from(files);
  let successful = 0;
  let failed = 0;

  toast.info("Uploading Files", `Processing ${fileArray.length} files...`, {
    showProgress: true,
  });

  for (const file of fileArray) {
    try {
      await api.upload(file);
      successful++;
    } catch (error) {
      failed++;
    }
  }

  if (failed === 0) {
    toast.success(
      "All Files Uploaded",
      `${successful} files uploaded successfully`
    );
  } else {
    toast.warning(
      "Upload Complete with Errors",
      `${successful} succeeded, ${failed} failed`,
      {
        actions: [
          {
            label: "View Details",
            onClick: () => showUploadDetails(),
          },
          {
            label: "Retry Failed",
            onClick: () => retryFailedUploads(),
          },
        ],
      }
    );
  }
}
</script>

File Size Error

vue
<script setup>
const toast = useToast();
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB

function handleFileSelect(event) {
  const file = event.target.files[0];

  if (file.size > MAX_FILE_SIZE) {
    toast.error("File Too Large", `${file.name} exceeds the 10MB limit`, {
      actions: [
        {
          label: "Compress File",
          onClick: () => openCompressor(file),
        },
      ],
    });
    event.target.value = ""; // Clear input
    return;
  }

  uploadFile(file);
}
</script>

Login/Authentication Forms

Successful Login

vue
<script setup>
const toast = useToast();
const router = useRouter();

async function handleLogin(credentials) {
  try {
    const user = await auth.login(credentials);

    toast.success("Welcome Back!", `Logged in as ${user.name}`, {
      avatar: {
        type: "image",
        src: user.avatar,
      },
    });

    router.push("/dashboard");
  } catch (error) {
    toast.error("Login Failed", error.message);
  }
}
</script>

Invalid Credentials

vue
<script setup>
const toast = useToast();

async function handleLogin(credentials) {
  try {
    await auth.login(credentials);
  } catch (error) {
    toast.error(
      "Login Failed",
      "Invalid email or password. Please try again.",
      {
        actions: [
          {
            label: "Forgot Password?",
            onClick: () => navigateTo("/forgot-password"),
          },
        ],
      }
    );
  }
}
</script>

Two-Factor Authentication

vue
<script setup>
const toast = useToast();

async function sendVerificationCode(email) {
  try {
    await auth.send2FA(email);

    toast.info(
      "Verification Code Sent",
      "Check your email for the 6-digit code",
      {
        icon: "i-lucide-mail",
        showProgress: true,
        duration: 8000,
      }
    );
  } catch (error) {
    toast.error("Failed to Send", error.message);
  }
}
</script>

Registration Forms

Account Created

vue
<script setup>
const toast = useToast();

async function handleRegistration(userData) {
  try {
    await api.register(userData);

    toast.success(
      "Account Created!",
      "Welcome to our platform. Please verify your email.",
      {
        actions: [
          {
            label: "Verify Email",
            onClick: () => navigateTo("/verify-email"),
          },
          {
            label: "Complete Profile",
            onClick: () => navigateTo("/profile/edit"),
          },
        ],
        duration: 10000,
      }
    );
  } catch (error) {
    toast.error("Registration Failed", error.message);
  }
}
</script>

Email Already Exists

vue
<script setup>
const toast = useToast();

async function checkEmail(email) {
  const exists = await api.checkEmailExists(email);

  if (exists) {
    toast.warning("Email Already Registered", "This email is already in use", {
      actions: [
        { label: "Login Instead", onClick: () => navigateTo("/login") },
        { label: "Forgot Password?", onClick: () => navigateTo("/forgot") },
      ],
    });
    return false;
  }

  return true;
}
</script>

Auto-Save Forms

Draft Saved

vue
<script setup>
const toast = useToast();
const content = ref("");
let saveTimeout = null;

watch(content, () => {
  clearTimeout(saveTimeout);
  saveTimeout = setTimeout(autoSave, 2000);
});

async function autoSave() {
  try {
    await api.saveDraft(content.value);

    toast.success("Draft Saved", "Changes saved automatically", {
      duration: 2000,
      position: "bottom-right",
    });
  } catch (error) {
    toast.error("Save Failed", "Could not save draft", {
      duration: 3000,
    });
  }
}
</script>

Form Recovery

Unsaved Changes Warning

vue
<script setup>
const toast = useToast();
const hasUnsavedChanges = ref(true);

onBeforeRouteLeave((to, from, next) => {
  if (hasUnsavedChanges.value) {
    toast.warning(
      "Unsaved Changes",
      "You have unsaved changes. What would you like to do?",
      {
        duration: Infinity,
        actions: [
          {
            label: "Save & Leave",
            onClick: async () => {
              await saveChanges();
              next();
            },
          },
          {
            label: "Discard",
            onClick: () => {
              hasUnsavedChanges.value = false;
              next();
            },
          },
          {
            label: "Stay",
            onClick: () => {
              toast.clear();
              next(false);
            },
          },
        ],
      }
    );
    next(false);
  } else {
    next();
  }
});
</script>