Skip to content

Commit 2f26e92

Browse files
posthog-eu[bot]justinegeffenchristopher-hakkaart
authored
fix(search): guard against key-less keydown events in search bar (#1691)
The swizzled SearchBar uses `useDocSearchKeyboardEvents` from typesense-docsearch-react, which registers a global keydown listener that calls `event.key.toLowerCase()` with no guard. Synthetic keydown events dispatched by password managers, autofill, or browser extensions (seen on Safari) can arrive without a `key`, so `event.key` is undefined and the handler throws `undefined is not an object (evaluating 'e.key.toLowerCase')`. Install a capture-phase keydown listener that runs before the upstream handler and swallows malformed, key-less events via `stopImmediatePropagation()`. A real user keystroke always carries a `key`, so nothing legitimate is affected. Generated-By: PostHog Code Task-Id: e789835e-7941-4ae9-b98e-056e87ff47b1 Co-authored-by: posthog-eu[bot] <226701856+posthog-eu[bot]@users.noreply.github.com> Co-authored-by: Justine Geffen <justinegeffen@users.noreply.github.com> Co-authored-by: Chris Hakkaart <chris.hakkaart@seqera.io>
1 parent 9de04a6 commit 2f26e92

1 file changed

Lines changed: 23 additions & 1 deletion

File tree

src/theme/SearchBar/index.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* themeConfig.typesense.productRoutes.
1111
*/
1212

13-
import React, {useState, useRef, useCallback, useMemo} from 'react';
13+
import React, {useState, useRef, useCallback, useEffect, useMemo} from 'react';
1414
// @ts-ignore
1515
import {createPortal} from 'react-dom';
1616
// @ts-ignore
@@ -312,6 +312,28 @@ function DocSearch({
312312
[onClose],
313313
);
314314

315+
// `useDocSearchKeyboardEvents` (from typesense-docsearch-react) registers a
316+
// global keydown listener that calls `event.key.toLowerCase()` with no guard.
317+
// Synthetic keydown events dispatched by password managers, autofill, or
318+
// browser extensions (notably on Safari) can arrive without a `key`, making
319+
// `event.key` undefined and throwing `undefined is not an object`. We install
320+
// our own capture-phase listener first so it runs before the upstream handler
321+
// and swallows these malformed, key-less events. A real user keystroke always
322+
// carries a `key`, so nothing legitimate is affected.
323+
useEffect(() => {
324+
function guardKeylessKeydown(event: KeyboardEvent) {
325+
if (!event.key) {
326+
event.stopImmediatePropagation();
327+
}
328+
}
329+
window.addEventListener('keydown', guardKeylessKeydown, {capture: true});
330+
return () => {
331+
window.removeEventListener('keydown', guardKeylessKeydown, {
332+
capture: true,
333+
});
334+
};
335+
}, []);
336+
315337
useDocSearchKeyboardEvents({
316338
isOpen,
317339
onOpen,

0 commit comments

Comments
 (0)