Home/Docs/Patterns

Patterns

Common patterns and best practices for using toast notifications effectively.

Form Submission Pattern

Using toast notifications to provide feedback during form submissions is one of the most common patterns.

Live Example

Try submitting the form with empty fields to see validation toast.

Implementation

// Form submission pattern with toast
const handleSubmit = async (e) => {
  e.preventDefault();
  
  // Validate form
  if (!isValid) {
    toast.error({
      title: 'Validation Error',
      description: 'Please check your inputs'
    });
    return;
  }
  
  // Show loading state
  const loadingId = toast.loading({
    title: 'Submitting',
    description: 'Processing your request...'
  });
  
  try {
    // Call API
    const response = await submitFormData(formData);
    
    // Update toast on success
    toast.update(loadingId, {
      variant: 'success',
      title: 'Success',
      description: 'Your form was submitted successfully',
      duration: 3000
    });
    
    // Reset form
    resetForm();
  } catch (error) {
    // Update toast on error
    toast.update(loadingId, {
      variant: 'error',
      title: 'Error',
      description: error.message || 'Something went wrong',
      duration: 5000
    });
  }
};

Promise-based Pattern

Using toast.promise() to handle async operations elegantly.

Live Example

How it works:

  1. Click the button to start an async operation
  2. A loading toast appears immediately
  3. When the promise resolves or rejects (randomly in this demo), the toast updates accordingly
  4. The promise result is still available to use in your code

Implementation

// Promise-based toast pattern
const fetchData = async () => {
  try {
    const result = await toast.promise(
      // Your async operation
      api.fetchUserData(userId),
      // Toast configurations for each state
      {
        loading: {
          title: 'Loading',
          description: 'Fetching user data...'
        },
        success: (data) => ({
          title: 'Success',
          description: `Loaded profile for ${data.name}`
        }),
        error: (err) => ({
          title: 'Error',
          description: err.message
        })
      }
    );
    
    // Work with the result
    setUserData(result);
  } catch (error) {
    // Additional error handling if needed
    console.error(error);
  }
};

Multi-step Process Pattern

Using toast updates to show progress through a multi-step operation.

Live Example

Tip:

This pattern is great for complex operations like file uploads, multi-stage form submissions, or wizard-like processes where you want to keep the user informed without blocking the UI.

Implementation

// Multi-step toast pattern
const startProcess = () => {
  // Create initial toast
  const id = toast.loading({
    title: 'Step 1/3',
    description: 'Initializing process...'
  });
  
  // Update for each step
  processStep1()
    .then(() => {
      toast.update(id, {
        title: 'Step 2/3',
        description: 'Processing data...'
      });
      return processStep2();
    })
    .then(() => {
      toast.update(id, {
        title: 'Step 3/3',
        description: 'Finalizing...'
      });
      return processStep3();
    })
    .then(() => {
      toast.update(id, {
        variant: 'success',
        title: 'Complete',
        description: 'All steps completed successfully',
        duration: 3000
      });
    })
    .catch((error) => {
      toast.update(id, {
        variant: 'error',
        title: 'Process Failed',
        description: error.message,
        duration: 3000
      });
    });
};

More Usage Patterns

Sequential Toasts

Show multiple toasts in sequence to guide users through a process.

Conditional Toast Variations

Use different toast types based on conditions.

Interactive Component Pattern

Create rich, interactive notifications with custom components.

// Custom interactive component pattern
const notifyUser = (userId, message) => {
  toast.custom(
    <div className="p-4 bg-blue-600 rounded-lg">
      <h3 className="font-medium text-white">{message.title}</h3>
      <p className="text-blue-100 text-sm">{message.content}</p>
      <div className="mt-3 flex space-x-2">
        <button 
          className="px-3 py-1 bg-white text-blue-600 rounded"
          onClick={() => {
            toast.dismiss();
            navigateToChat(userId);
          }}
        >
          Reply
        </button>
        <button 
          className="px-3 py-1 bg-transparent border border-white text-white rounded"
          onClick={() => toast.dismiss()}
        >
          Dismiss
        </button>
      </div>
    </div>,
    {
      duration: 0, // No auto-dismiss
      position: 'bottom-right'
    }
  );
};

Toast Notification Best Practices

Keep It Brief

Toast notifications should be concise and focused on a single piece of information. Use clear, actionable language.

Use Appropriate Variants

Match the toast variant to the message type: success for confirmations, error for problems, warning for cautions, and info for general updates.

Consider Duration

Adjust duration based on importance and content length. Critical errors might need longer display times, while simple confirmations can be brief.

Avoid Toast Overload

Don't spam users with too many notifications. Group related messages when possible and prioritize important information.

Accessible Notifications

Ensure your toasts are accessible to all users, including those using screen readers. React Toast Kit handles this automatically with proper ARIA attributes.