Skip to content

Commit 78fabd8

Browse files
te6-inclaude
andcommitted
fix(snackbar): only pause on keyboard focus using :focus-visible (#1209)
* fix(snackbar): only pause on keyboard focus using :focus-visible Previously, onFocus handler would pause the snackbar timer on any focus event including mouse clicks/taps. This caused the snackbar to persist indefinitely when clicked. Now uses :focus-visible to detect keyboard-initiated focus: - Keyboard Tab → pause timer (accessibility for screen reader users) - Mouse click → don't pause (timer continues normally) - If :focus-visible not supported → don't pause (safe fallback) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs * fix(snackbar): remove unnecessary :focus-within check :focus-within doesn't distinguish between keyboard and mouse focus, so it would cause pause on mouse click as well. Since :focus-visible is applied to the focused element itself (including buttons focused via keyboard), checking event.target.matches(":focus-visible") alone is sufficient. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: changeset --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 800f9a8 commit 78fabd8

File tree

4 files changed

+19
-3
lines changed

4 files changed

+19
-3
lines changed

.changeset/huge-clouds-design.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@seed-design/react-snackbar": patch
3+
---
4+
5+
Snackbar 타이머가 멈추는 기준을 `focus`에서 `focus-visible`로 수정하여 `pauseOnInteraction={true}`인 경우 Snackbar가 닫히지 않는 문제를 수정합니다.

bun.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react-headless/snackbar/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"dependencies": {
3030
"@radix-ui/react-compose-refs": "^1.1.2",
3131
"@seed-design/dom-utils": "1.0.0",
32-
"@seed-design/react-primitive": "1.0.0"
32+
"@seed-design/react-primitive": "1.0.0",
33+
"@seed-design/react-supports": "0.0.1"
3334
},
3435
"devDependencies": {
3536
"@types/react": "^19.1.6",

packages/react-headless/snackbar/src/useSnackbar.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ariaAttr, buttonProps, dataAttr, elementProps } from "@seed-design/dom-utils";
2+
import { useSupports } from "@seed-design/react-supports";
23
import { useCallback, useEffect, useMemo, useState } from "react";
34
import { useSafeOffset } from "./useSafeOffset";
45

@@ -145,6 +146,7 @@ export function useSnackbar(props: UseSnackbarProps) {
145146
const { state, currentSnackbar, visible, queue, visibleDuration, events } =
146147
useSnackbarState(props);
147148
const { overlapTracker, regionRef, regionStyle, safeOffset } = useSafeOffset();
149+
const isFocusVisibleSupported = useSupports("selector(:focus-visible)");
148150

149151
return useMemo(
150152
() => ({
@@ -189,8 +191,14 @@ export function useSnackbar(props: UseSnackbarProps) {
189191
"--snackbar-remove-delay": `${currentSnackbar?.removeDelay ?? 0}ms`,
190192
"--snackbar-duration": `${visibleDuration}ms`,
191193
} as React.CSSProperties,
192-
onFocus() {
193-
events.pause();
194+
onFocus(event) {
195+
// if :focus-visible not supported, do not pause on focus
196+
if (!isFocusVisibleSupported) return;
197+
198+
// only pause if focus is visible (focused using keyboard) || action label has focus
199+
if (event.target.matches(":focus-visible")) {
200+
events.pause();
201+
}
194202
},
195203
onBlur() {
196204
events.resume();
@@ -221,6 +229,7 @@ export function useSnackbar(props: UseSnackbarProps) {
221229
regionStyle,
222230
overlapTracker,
223231
regionRef,
232+
isFocusVisibleSupported,
224233
],
225234
);
226235
}

0 commit comments

Comments
 (0)