From 478e1f9248f870ce524b0886967f7edf9314a549 Mon Sep 17 00:00:00 2001 From: lubauss Date: Sat, 21 Feb 2026 19:53:31 +0100 Subject: [PATCH] feat: add optional close button for toast dismissal Add a `closeButton` prop to `` that renders an X dismiss button on each toast, visible on hover. This provides an alternative to swipe-to-dismiss for desktop users, especially useful for sticky toasts (duration: null) that don't auto-dismiss. - closeButton defaults to false (no visual change unless opted in) - Accessible: role="button", tabIndex, aria-label, keyboard support - Swipe-to-dismiss still works alongside the button --- src/sileo.tsx | 25 +++++++++++++++++++++++++ src/styles.css | 30 ++++++++++++++++++++++++++++++ src/toast.tsx | 3 +++ 3 files changed, 58 insertions(+) diff --git a/src/sileo.tsx b/src/sileo.tsx index 0a7336f..9b0977a 100644 --- a/src/sileo.tsx +++ b/src/sileo.tsx @@ -65,6 +65,7 @@ interface SileoProps { canExpand?: boolean; interruptKey?: string; refreshKey?: string; + closeButton?: boolean; onMouseEnter?: MouseEventHandler; onMouseLeave?: MouseEventHandler; onDismiss?: () => void; @@ -133,6 +134,7 @@ export const Sileo = memo(function Sileo({ canExpand, interruptKey, refreshKey, + closeButton = false, onMouseEnter, onMouseLeave, onDismiss, @@ -652,6 +654,29 @@ export const Sileo = memo(function Sileo({ + {closeButton && onDismiss && ( +
{ + e.preventDefault(); + e.stopPropagation(); + onDismiss(); + }} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + e.stopPropagation(); + onDismiss(); + } + }} + > + +
+ )} + {hasDesc && (
; + closeButton?: boolean; } /* ------------------------------ Global State ------------------------------ */ @@ -218,6 +219,7 @@ export function Toaster({ position = "top-right", offset, options, + closeButton = false, }: SileoToasterProps) { const [toasts, setToasts] = useState(store.toasts); const [activeId, setActiveId] = useState(); @@ -423,6 +425,7 @@ export function Toaster({ onMouseEnter={h.enter} onMouseLeave={h.leave} onDismiss={h.dismiss} + closeButton={closeButton} /> ); })}