Feedback & Loading
Alerts, toasts, spinners, and loading state components.
Show user feedback with Alert for inline messages, toast (Sonner) for transient notifications, Spinner for action indicators, Progress for determinate progress, LoadingOverlay/GlobalLoader for blocking states, and Tooltip for hover hints. Add Toaster to your root layout once.
This guide is part of the UI Components documentation.
Feedback and loading components communicate system status to users - from error messages and success confirmations to progress indicators and loading states - ensuring users always know what's happening.
Use Alert when: displaying persistent messages that users need to read (errors, warnings, info).
- Use toast when: confirming transient actions (save successful, item deleted).
- Use Spinner/Progress when: operations take >300ms.
- If unsure: toast for user-triggered actions, Alert for system-initiated messages.
Alert
Alert message for important information.
import { Alert, AlertTitle, AlertDescription } from '@kit/ui/alert';<Alert> <AlertTitle>Information</AlertTitle> <AlertDescription> This is an informational alert message. </AlertDescription></Alert><Alert variant="destructive"> <AlertTitle>Error</AlertTitle> <AlertDescription> Something went wrong. Please try again. </AlertDescription></Alert>With Icon
import { TriangleAlert, CheckCircle } from 'lucide-react';<Alert variant="destructive"> <TriangleAlert className="h-4 w-4" /> <AlertTitle>Error</AlertTitle> <AlertDescription>Operation failed.</AlertDescription></Alert><Alert> <CheckCircle className="h-4 w-4" /> <AlertTitle>Success</AlertTitle> <AlertDescription>Operation completed.</AlertDescription></Alert>Toast (Sonner)
Toast notifications using Sonner.
import { toast } from '@kit/ui/sonner';// Simple toaststoast.success('Operation successful');toast.error('Something went wrong');toast.info('New message received');toast.warning('Please review your input');// With descriptiontoast.success('Saved', { description: 'Your changes have been saved.',});// Promise-based toastawait toast.promise(saveData(), { loading: 'Saving...', success: 'Data saved!', error: 'Failed to save',});Toaster Setup
Add to your root layout:
import { Toaster } from '@kit/ui/sonner';export default function RootLayout({ children }) { return ( <html> <body> {children} <Toaster /> </body> </html> );}Spinner
Loading spinner animation.
import { Spinner } from '@kit/ui/spinner';<Spinner /><Spinner className="h-8 w-8" /><Spinner className="h-4 w-4 text-primary" />In Button
<Button disabled={isPending}> {isPending ? ( <> <Spinner className="mr-2 h-4 w-4" /> Loading... </> ) : ( 'Submit' )}</Button>Progress
Progress bar indicator.
import { Progress } from '@kit/ui/progress';<Progress value={33} /><Progress value={66} /><Progress value={100} />Loading Overlay
Semi-transparent overlay with spinner.
import { LoadingOverlay } from '@kit/ui/loading-overlay';<div className="relative"> <Content /> {isLoading && <LoadingOverlay />}</div>Global Loader
Full-page loading state.
import { GlobalLoader } from '@kit/ui/global-loader';<GlobalLoader />{/* With options */}<GlobalLoader displayLogo fullPage displaySpinner displayTopLoadingBar/>Tooltip
Hover tooltip for additional information.
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@kit/ui/tooltip';<TooltipProvider> <Tooltip> <TooltipTrigger> <Button variant="outline" size="icon"> <HelpCircle className="h-4 w-4" /> </Button> </TooltipTrigger> <TooltipContent> <p>Helpful information here</p> </TooltipContent> </Tooltip></TooltipProvider>In MakerKit, we use toast.promise() heavily for Server Action feedback - it handles loading, success, and error states in one call, which users find clearer than separate loading spinners.
Common Pitfalls
- Missing Toaster in layout: Toast won't appear without
<Toaster />in your root layout. Add it once and it works everywhere. - Alert vs Toast confusion: Use Alert for persistent, inline messages. Use toast for transient notifications that auto-dismiss.
- Tooltip without TooltipProvider: Tooltips need
TooltipProvideras a parent. Wrap your app or component tree once. - Spinner without sizing: Spinner needs explicit dimensions via className. Default is small - use
className="h-8 w-8"for visibility. - LoadingOverlay without relative parent: LoadingOverlay uses absolute positioning. Its parent container needs
position: relative. - Progress value out of range: Progress expects value 0-100. Values outside this range may cause visual glitches.
Frequently Asked Questions
How do I show a toast from a Server Action?
Can I customize toast duration?
What's the difference between LoadingOverlay and GlobalLoader?
How do I show loading state during navigation?
Can I use Alert in Server Components?
Next: Utilities →