fix: modal stole input focus on every keystroke
The focus/scroll-lock effect depended on onClose (a new function each render), so it re-ran on every keystroke and refocused the panel. Split focus-on-open from the Escape listener so inputs in modals keep focus while typing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -17,19 +17,26 @@ const sizes = { sm: 'max-w-sm', md: 'max-w-lg', lg: 'max-w-2xl' }
|
||||
export function Modal({ open, onClose, title, children, footer, size = 'md' }: Props) {
|
||||
const panelRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
// Lock scroll + focus the panel only when the modal opens (not on every render,
|
||||
// otherwise typing in an input would keep stealing focus back to the panel).
|
||||
useEffect(() => {
|
||||
if (!open) return
|
||||
const prev = document.body.style.overflow
|
||||
document.body.style.overflow = 'hidden'
|
||||
panelRef.current?.focus()
|
||||
return () => {
|
||||
document.body.style.overflow = prev
|
||||
}
|
||||
}, [open])
|
||||
|
||||
// Escape-to-close listener kept separate so its onClose dependency can change freely.
|
||||
useEffect(() => {
|
||||
if (!open) return
|
||||
function onKey(e: KeyboardEvent) {
|
||||
if (e.key === 'Escape') onClose()
|
||||
}
|
||||
document.addEventListener('keydown', onKey)
|
||||
const prev = document.body.style.overflow
|
||||
document.body.style.overflow = 'hidden'
|
||||
panelRef.current?.focus()
|
||||
return () => {
|
||||
document.removeEventListener('keydown', onKey)
|
||||
document.body.style.overflow = prev
|
||||
}
|
||||
return () => document.removeEventListener('keydown', onKey)
|
||||
}, [open, onClose])
|
||||
|
||||
if (!open) return null
|
||||
|
||||
Reference in New Issue
Block a user