Feedback patterns are UI states that communicate system status to users: loading indicators, success/error toasts, empty states, and progress indicators. Consistent feedback helps users understand what's happening and what to do next.
// Success — brief, no action needed
toast.success("Changes saved")
// Error — explain what happened, offer action
toast.error("Failed to save changes", {
description: "Check your connection and try again",
action: { label: "Retry", onClick: handleRetry }
})
// Warning — alert to potential issue
toast.warning("Unsaved changes", {
description: "Your changes will be lost if you leave"
})
// Info — neutral information
toast.info("New version available")
Is data loading?
├── Yes → Is layout known?
│ ├── Yes → Is it expected to take > 500ms?
│ │ ├── Yes → Use skeleton
│ │ └── No → Use spinner (or nothing for < 200ms)
│ └── No → Use page spinner
└── No → Is there data?
├── Yes → Show content
└── No → What's the reason?
├── First time → Empty state with CTA
├── No results → Empty state with "clear filters"
└── Error → Error state with retry
// Contextual empty state with action
}
title="No projects yet"
description="Create your first project to get started."
action={}
/>
Auto-dismissing errors
// Error disappears before user can read it
toast.error("Failed to save", { duration: 3000 })
// Error persists until acknowledged
toast.error("Failed to save", {
duration: Infinity,
action: { label: "Retry", onClick: handleRetry }
})