Guia de Toast
Guia de UsoSistema de notificações toast elegante e customizável usando Sonner.
Preview
Diferentes tipos de notificações toast disponíveis
Instalação
Como instalar e configurar o Sonner em seu projeto
Instalação
npm install sonner⚠️ Importante: O componente Sonner original usa next-themes que pode causar conflitos. Use a versão standalone ou implemente manualmente conforme mostrado no tutorial.
1. Componente Toaster Standalone
Versão independente sem dependências do Next.js
components/ToasterStandalone.tsx
"use client";
import { Toaster as Sonner, ToasterProps, toast } from "sonner";
import React from "react";
// Componente Toaster Standalone - sem dependência do next-themes
export function ToasterStandalone({
theme = "light",
...props
}: ToasterProps & { theme?: "light" | "dark" | "contrast" }) {
return (
<Sonner
theme={theme}
className="toaster group custom-toast-position"
position="top-right"
style={
{
"--normal-bg": "var(--popover)",
"--normal-text": "var(--popover-foreground)",
"--normal-border": "var(--border)",
"--success-bg": "#dcfce7",
"--success-text": "#15803d",
"--success-border": "#16a34a",
"--error-bg": "#fef2f2",
"--error-text": "#dc2626",
"--error-border": "#ef4444",
"--warning-bg": "#fefce8",
"--warning-text": "#ca8a04",
"--warning-border": "#eab308",
"--info-bg": "#eff6ff",
"--info-text": "#2563eb",
"--info-border": "#3b82f6",
} as React.CSSProperties
}
toastOptions={{
style: {
border: "1px solid var(--normal-border)",
},
classNames: {
success: "toast-success",
error: "toast-error",
warning: "toast-warning",
info: "toast-info",
},
}}
{...props}
/>
);
}2. Hook useToast Simplificado
Hook para facilitar o uso dos toasts
hooks/useToastStandalone.ts
// Hook simplificado para usar toast sem dependências externas
export function useToastStandalone() {
const showToast = {
success: (message: string, options?: { description?: string }) => {
toast.success(message, options);
},
error: (message: string, options?: { description?: string }) => {
toast.error(message, options);
},
info: (message: string, options?: { description?: string }) => {
toast.info(message, options);
},
warning: (message: string, options?: { description?: string }) => {
toast.warning(message, options);
},
promise: <T,>(
promise: Promise<T>,
options: {
loading: string;
success: string | ((data: T) => string);
error: string | ((error: any) => string);
}
) => {
toast.promise(promise, options);
},
dismiss: (toastId?: string | number) => {
toast.dismiss(toastId);
},
};
return { toast: showToast };
}3. Configuração no Layout
Como adicionar o Toaster no seu layout principal
app/layout.tsx
import { ToasterStandalone } from "@/components/ToasterStandalone";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="pt-BR">
<body>
{children}
<ToasterStandalone />
</body>
</html>
);
}4. CSS Personalizado (Opcional)
Estilos customizados baseados no hollow-UI
globals.css
/* Toast colors for better UX */
.toast-success {
background-color: var(--success-bg);
color: var(--success-text);
border-color: var(--success-border);
}
.toast-error {
background-color: var(--error-bg);
color: var(--error-text);
border-color: var(--error-border);
}
.toast-warning {
background-color: var(--warning-bg);
color: var(--warning-text);
border-color: var(--warning-border);
}
.toast-info {
background-color: var(--info-bg);
color: var(--info-text);
border-color: var(--info-border);
}
/* Dark theme adjustments for toasts */
.dark .toast-success {
background-color: #064e3b;
color: #6ee7b7;
border-color: #059669;
}
.dark .toast-error {
background-color: #7f1d1d;
color: #fca5a5;
border-color: #dc2626;
}
.dark .toast-warning {
background-color: #78350f;
color: #fcd34d;
border-color: #d97706;
}
.dark .toast-info {
background-color: #1e3a8a;
color: #93c5fd;
border-color: #2563eb;
}
/* Contrast theme adjustments for toasts */
.contrast .toast-success {
background-color: #000000;
color: #00ff00;
border-color: #00ff00;
}
.contrast .toast-error {
background-color: #000000;
color: #ff0000;
border-color: #ff0000;
}
.contrast .toast-warning {
background-color: #000000;
color: #ffff00;
border-color: #ffff00;
}
.contrast .toast-info {
background-color: #000000;
color: #00ffff;
border-color: #00ffff;
}
.custom-toast-position {
z-index: 9999;
}5. Exemplos de Uso
Diferentes formas de usar os toasts em seus componentes
Uso Básico
Componente.tsx
"use client";
import { useToastStandalone } from "@/hooks/useToastStandalone";
import { Button } from "@/components/ui/button";
export function MeuComponente() {
const { toast } = useToastStandalone();
const handleSave = () => {
// Simula uma operação de salvamento
try {
// ... lógica de salvamento
toast.success("Dados salvos com sucesso!");
} catch (error) {
toast.error("Erro ao salvar os dados");
}
};
return (
<Button onClick={handleSave}>
Salvar
</Button>
);
}Promise Toast (Operações Assíncronas)
AsyncOperations.tsx
const { toast } = useToastStandalone();
const handleAsyncOperation = async () => {
const promise = fetch('/api/data').then(res => res.json());
toast.promise(promise, {
loading: 'Carregando dados...',
success: (data) => `${data.length} itens carregados!`,
error: 'Erro ao carregar dados',
});
};Toast com Descrição
DetailedToast.tsx
const { toast } = useToastStandalone();
const showDetailedToast = () => {
toast.success("Upload concluído", {
description: "3 arquivos foram enviados com sucesso para o servidor"
});
};Controle Manual
ManualControl.tsx
const { toast } = useToastStandalone();
const showPersistentToast = () => {
const toastId = toast.info("Processamento em andamento...", {
description: "Esta operação pode levar alguns minutos"
});
// Depois de um tempo, remover o toast
setTimeout(() => {
toast.dismiss(toastId);
toast.success("Processamento concluído!");
}, 5000);
};6. Integração com Sistema de Gestão
Como usar toasts em sistemas de gestão e monitoramento
StatusReportActions.tsx
import { useToastStandalone } from "@/hooks/useToastStandalone";
export function StatusReportActions() {
const { toast } = useToastStandalone();
const handleSubmitTask = async (taskData: any) => {
const submitPromise = fetch('/api/task/submit', {
method: 'POST',
body: JSON.stringify(taskData),
});
toast.promise(submitPromise, {
loading: 'Enviando tarefa...',
success: 'Tarefa enviada com sucesso! Você receberá atualizações por email.',
error: 'Falha ao enviar tarefa. Tente novamente.',
});
};
const handleStatusUpdate = (status: string) => {
switch (status) {
case 'CONCLUÍDO':
toast.success('Tarefa concluída', {
description: 'Todas as ações foram implementadas'
});
break;
case 'EM_ANALISE':
toast.info('Tarefa em análise', {
description: 'A equipe está revisando'
});
break;
case 'CANCELADO':
toast.warning('Tarefa foi cancelada', {
description: 'Entre em contato com o responsável para mais informações'
});
break;
}
};
return (
<div className="space-y-4">
<Button onClick={() => handleSubmitPR({})}>
Enviar Tarefa
</Button>
<Button onClick={() => handleStatusUpdate('CONCLUÍDO')}>
Simular Status Update
</Button>
</div>
);
}7. Boas Práticas
Diretrizes para usar toasts de forma eficaz
✅ Faça
- Use toasts para feedback imediato
- Seja conciso nas mensagens
- Use o tipo apropriado (success, error, warning, info)
- Forneça contexto com descrições quando necessário
- Use promise toasts para operações assíncronas
❌ Evite
- Toasts para informações críticas
- Mensagens muito longas
- Múltiplos toasts simultâneos
- Toasts que não se autodispensam
- Uso excessivo que pode irritar o usuário
💡 Dica de Acessibilidade
Os toasts são automaticamente anunciados por leitores de tela. Certifique-se de que as mensagens sejam claras e informativas mesmo quando lidas fora do contexto visual.



