# Feedback & Loading

> Alerts, toasts, spinners, and loading state components.

*Canonical: https://makerkit.dev/docs/nextjs-prisma/ui-components/feedback-and-loading*

---

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](./overview) 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.

```typescript
import { Alert, AlertTitle, AlertDescription } from '@kit/ui/alert';
```

```tsx
<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

```tsx
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.

```typescript
import { toast } from '@kit/ui/sonner';
```

```tsx
// Simple toasts
toast.success('Operation successful');
toast.error('Something went wrong');
toast.info('New message received');
toast.warning('Please review your input');

// With description
toast.success('Saved', {
  description: 'Your changes have been saved.',
});

// Promise-based toast
await toast.promise(saveData(), {
  loading: 'Saving...',
  success: 'Data saved!',
  error: 'Failed to save',
});
```

### Toaster Setup

Add to your root layout:

```tsx
import { Toaster } from '@kit/ui/sonner';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Toaster />
      </body>
    </html>
  );
}
```

## Spinner

Loading spinner animation.

```typescript
import { Spinner } from '@kit/ui/spinner';
```

```tsx
<Spinner />
<Spinner className="h-8 w-8" />
<Spinner className="h-4 w-4 text-primary" />
```

### In Button

```tsx
<Button disabled={isPending}>
  {isPending ? (
    <>
      <Spinner className="mr-2 h-4 w-4" />
      Loading...
    </>
  ) : (
    'Submit'
  )}
</Button>
```

## Progress

Progress bar indicator.

```typescript
import { Progress } from '@kit/ui/progress';
```

```tsx
<Progress value={33} />
<Progress value={66} />
<Progress value={100} />
```

## Loading Overlay

Semi-transparent overlay with spinner.

```typescript
import { LoadingOverlay } from '@kit/ui/loading-overlay';
```

```tsx
<div className="relative">
  <Content />
  {isLoading && <LoadingOverlay />}
</div>
```

## Global Loader

Full-page loading state.

```typescript
import { GlobalLoader } from '@kit/ui/global-loader';
```

```tsx
<GlobalLoader />

{/* With options */}
<GlobalLoader
  displayLogo
  fullPage
  displaySpinner
  displayTopLoadingBar
/>
```

## Tooltip

Hover tooltip for additional information.

```typescript
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@kit/ui/tooltip';
```

```tsx
<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 `TooltipProvider` as 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.

{% faq
   title="Frequently Asked Questions"
   items=[
     {"question": "How do I show a toast from a Server Action?", "answer": "Server Actions can't call toast directly. Return success/error status and call toast in the client component that invoked the action."},
     {"question": "Can I customize toast duration?", "answer": "Yes. Pass duration in milliseconds: toast.success('Saved', { duration: 5000 }). Default is typically 4 seconds."},
     {"question": "What's the difference between LoadingOverlay and GlobalLoader?", "answer": "LoadingOverlay covers a specific container (relative positioned). GlobalLoader covers the entire viewport for full-page loading states."},
     {"question": "How do I show loading state during navigation?", "answer": "Use GlobalLoader with displayTopLoadingBar prop for a thin progress bar. Combine with Next.js loading.tsx for route transitions."},
     {"question": "Can I use Alert in Server Components?", "answer": "Yes. Alert is a static display component with no client-side interactivity, so it works in Server Components without 'use client'."}
   ]
/%}

---

**Next:** [Utilities →](./utilities)
