toast("알림이 도착했습니다", { description: "기본 알림입니다." })}>Default
toast.success("저장했습니다", { description: "변경 사항이 저장되었습니다." })}>Success
toast.error("저장하지 못했습니다", { description: "잠시 후 다시 시도하세요." })}>Error
toast.warning("저장 공간이 부족합니다", { description: "불필요한 파일을 정리하세요." })}>Warning
toast.info("새 버전이 있습니다")}>Info
toast.loading("처리 중입니다", { duration: 4000 })}>Loading
),
},
{
id: "action",
label: "Action / Close",
children: (
toast("파일을 삭제했습니다", { action: { label: "실행 취소", onClick: () => toast.success("복원했습니다") } })}>
Action
toast("변경 사항을 적용할까요?", {
description: "취소하면 이전 상태가 유지됩니다.",
duration: Infinity,
action: { label: "적용", onClick: () => undefined },
cancel: { label: "취소", onClick: () => undefined },
})
}
>
Action + Cancel
toast("닫기 버튼이 있는 알림", { closeButton: true, duration: Infinity })}>Close button
),
},
{
id: "promise",
label: "Promise",
children: (
toast.promise(wait(1500), { loading: "저장 중...", success: "저장했습니다", error: "저장하지 못했습니다" })}>
Promise → Success
toast.promise(wait(1500, true), { loading: "저장 중...", success: "저장했습니다", error: "저장하지 못했습니다" })}>
Promise → Error
),
},
{
id: "stack",
label: "Stack / Long",
children: (
{
toast("첫 번째 알림")
toast.success("두 번째 알림")
toast.error("세 번째 알림")
}}
>
Stack ×3
toast.info("긴 메시지 확인용 제목입니다. 좁은 화면에서도 줄바꿈되어야 합니다.", {
description: "설명도 길게 작성하면 여러 줄로 나뉘고 토스트 폭을 넘치지 않아야 합니다. 이 문장은 줄바꿈을 확인하기 위한 예시입니다.",
action: { label: "자세히 보기", onClick: () => undefined },
closeButton: true,
})
}
>
Long message
toast.dismiss()}>Dismiss all
),
},
].filter((s) => ids.includes(s.id))}
/>
)
}
const meta = { title: "Components/Feedback/Sonner", component: Toaster, parameters: { layout: "padded" } } satisfies Meta
export default meta
type Story = StoryObj
// Representative Story: buttons create real toasts through Sonner (types, action / cancel, close, promise, stack, long message).
export const All: Story = {
name: "Sonner",
parameters: { layout: "fullscreen", controls: { disable: true } },
render: () => (
),
}