Toast
Notificações toast com Sonner - sucesso, erro, carregamento e toasts personalizados em shadcn/ui.
Busque em todas as páginas da documentação
Notificações toast com Sonner - sucesso, erro, carregamento e toasts personalizados em shadcn/ui.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Cartão de receita de referência rápida - pronto para copiar e colar.
npx shadcn@latest add sonner// app/layout.tsx - adicione o Toaster
import { Toaster } from "@/components/ui/sonner";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Toaster />
</body>
</html>
);
}// Uso em qualquer lugar
import { toast } from "sonner";
toast("Notificação padrão");
toast.success("Salvo com sucesso!");
toast.error("Algo deu errado");
toast.info("Você sabia?");
toast.warning("Verifique sua entrada");
toast.loading("Processando...");Quando usar isso: Quando você precisar de feedback não bloqueante para ações do usuário - salvamentos, exclusões, erros e progresso de tarefas em segundo plano.
"use client";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
export function ToastShowcase() {
// Toasts simples
function showSuccess() {
toast.success("Perfil atualizado", {
description: "Suas alterações foram salvas.",
});
}
function showError() {
toast.error("Falha ao salvar", {
description: "Por favor, verifique sua conexão e tente novamente.",
action: {
label: "Tentar novamente",
onClick: () => console.log("Tentando novamente..."),
},
});
}
// Toast de promessa - mostra carregamento, depois sucesso ou erro
function handleSave() {
const savePromise = new Promise((resolve, reject) => {
setTimeout(() => {
Math.random() > 0.3 ? resolve("done") : reject(new Error("fail"));
}, 2000);
});
toast.promise(savePromise, {
loading: "Salvando alterações...",
success: "Alterações salvas!",
error: "Falha ao salvar. Tente novamente.",
});
}
// Toast personalizado com JSX
function showCustom() {
toast.custom((id) => (
<div className="flex items-center gap-3 rounded-lg border bg-white p-4 shadow-lg dark:bg-gray-950">
<div className="size-10 rounded-full bg-blue-100 flex items-center justify-center">
<span className="text-blue-600 text-lg">!</span>
</div>
<div className="flex-1">
<p className="text-sm font-medium">Nova mensagem de Alice</p>
<p className="text-xs text-muted-foreground">Ei, confira este recurso!</p>
</div>
<Button size="sm" variant="outline" onClick={() => toast.dismiss(id)}>
Dispensar
</Button>
</div>
));
}
// Toast de desfazer
function handleDelete() {
let undone = false;
toast("Item excluído", {
description: "O item foi movido para a lixeira.",
action: {
label: "Desfazer",
onClick: () => {
undone = true;
toast.success("Restaurado!");
},
},
onAutoClose: () => {
if (!undone) {
// Excluir permanentemente
console.log("Excluído permanentemente");
}
},
});
}
return (
<div className="flex flex-wrap gap-3">
<Button onClick={showSuccess}>Sucesso</Button>
<Button variant="destructive" onClick={showError}>Erro + Tentar novamente</Button>
<Button variant="outline" onClick={handleSave}>Toast de Promessa</Button>
<Button variant="secondary" onClick={showCustom}>Personalizado</Button>
<Button variant="ghost" onClick={handleDelete}>Excluir com Desfazer</Button>
</div>
);
}O que isso demonstra:
toast.promise para operações assíncronas com estados de carregamento/sucesso/errotoast.custom para toasts JSX totalmente personalizados<Toaster><Toaster> renderiza um contêiner de posição fixa que gerencia o empilhamento e as animações dos toaststoast() é uma chamada de função (não um hook) - chame-a de qualquer lugar, incluindo callbacks de actions do servidorConfiguração do Toaster:
<Toaster
position="top-right" // ou "top-left", "bottom-left", "bottom-right", "top-center", "bottom-center"
richColors // habilita fundos coloridos para sucesso/erro
closeButton // mostra um botão de fechar em cada toast
duration={5000} // duração padrão de fechamento automático em ms
expand={false} // se os toasts se expandem para mostrar tudo de uma vez
toastOptions={{
className: "border-border",
descriptionClassName: "text-muted-foreground",
}}
/>Toast na resposta de action do servidor:
// Action do servidor
"use server";
export async function updateProfile(formData: FormData) {
// ... lógica de atualização
return { success: true, message: "Perfil atualizado" };
}
// Componente cliente
async function handleSubmit(formData: FormData) {
const result = await updateProfile(formData);
if (result.success) {
toast.success(result.message);
} else {
toast.error(result.message);
}
}Toast persistente (sem fechamento automático):
const toastId = toast.loading("Enviando arquivo...", {
duration: Infinity,
});
// Mais tarde, atualize-o
toast.success("Upload concluído!", { id: toastId });
// Ou dispense-o
toast.dismiss(toastId);Toasts temáticos com richColors:
// Com <Toaster richColors />:
toast.success("Salvo!"); // fundo verde
toast.error("Falhou!"); // fundo vermelho
toast.info("Nota:"); // fundo azul
toast.warning("Cuidado:"); // fundo amarelo// toast retorna um ID de string
const id: string | number = toast("Olá");
// Dispensar um toast específico
toast.dismiss(id);
// Dispensar todos os toasts
toast.dismiss();
// toast.promise é genérico
const promise: Promise<User> = fetchUser();
toast.promise(promise, {
loading: "Carregando usuário...",
success: (user) => `Bem-vindo, ${user.name}!`, // user é tipado como User
error: (err) => `Erro: ${err.message}`,
});
// Função de renderização de toast personalizado
toast.custom((id: string | number) => (
<div>Conteúdo personalizado <button onClick={() => toast.dismiss(id)}>Fechar</button></div>
));<Toaster /> ausente - Se você esquecer de adicionar <Toaster /> ao seu layout, as chamadas toast() não farão nada. Correção: Adicione-o ao seu layout raiz.
Toast chamado durante a renderização - Chamar toast() dentro do corpo de um componente (não em um manipulador de eventos) dispara durante a renderização. Correção: Chame toast() em useEffect, manipuladores de eventos ou após actions do servidor.
Muitos toasts - Ações rápidas podem inundar a tela. Correção: Use toast.dismiss() antes de mostrar um novo toast, ou use id para atualizar um toast existente.
richColors e modo escuro - Sem richColors, toasts de sucesso/erro parecem os mesmos. Com ele, eles obtêm fundos coloridos que podem precisar de ajustes no modo escuro. Correção: Teste ambos os temas.
Sonner vs shadcn toast - O shadcn anteriormente tinha seu próprio componente de toast. A recomendação atual é Sonner. Correção: Use npx shadcn@latest add sonner, não o antigo componente toast.
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| react-hot-toast | Você quer uma alternativa leve com API semelhante | Sonner atende às suas necessidades |
| Notificações nativas do navegador | Você precisa de notificações em nível de SO (com permissão) | Feedback no aplicativo é suficiente |
| Alertas inline | O feedback está vinculado a uma seção específica da página | Você precisa de feedback não bloqueante e transitório |
| Snackbar (MUI) | Você usa Material UI | Você usa shadcn/ui |
<Toaster /> ao seu layout raiz (app/layout.tsx)toast() não farão nada silenciosamentenpx shadcn@latest add sonnertoast() - notificação padrãotoast.success() - feedback de sucessotoast.error() - feedback de errotoast.info() - informativotoast.warning() - avisotoast.loading() - spinner de carregamentotoast.promise(savePromise, {
loading: "Salvando alterações...",
success: "Alterações salvas!",
error: "Falha ao salvar. Tente novamente.",
});Ele transiciona automaticamente entre os estados de carregamento, sucesso e erro com base na promessa.
onAutoClose para realizar a exclusão real somente se o desfazer não foi clicadotoast() apenas em manipuladores de eventos, useEffect ou após respostas de actions do servidorconst toastId = toast.loading("Enviando arquivo...", {
duration: Infinity,
});
// Mais tarde, atualize ou dispense-o:
toast.success("Upload concluído!", { id: toastId });toast() ou toast.loading(){ id: toastId } para uma chamada subsequente de toast.success() ou toast.error()toast.custom((id) => (
<div className="flex items-center gap-3 rounded-lg border p-4 shadow-lg">
<p className="text-sm font-medium">Mensagem personalizada</p>
<Button size="sm" onClick={() => toast.dismiss(id)}>Dispensar</Button>
</div>
));npx shadcn@latest add sonner)toast em novos projetosconst promise: Promise<User> = fetchUser();
toast.promise(promise, {
loading: "Carregando usuário...",
success: (user) => `Bem-vindo, ${user.name}!`, // user é tipado como User
error: (err) => `Erro: ${err.message}`,
});top-right, top-left, top-centerbottom-right, bottom-left, bottom-center<Toaster position="top-right" />Revisado por Chris St. John·Última atualização: 16 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥