From 9d3b0ff611b25191e94b3e67c1c04fd16567cd70 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 4 Apr 2025 14:16:42 +0200 Subject: [PATCH] Fix `Unexpected undefined` crash in `Combobox` component with `virtual` mode (#3678) This PR fixes an issue where the `Combobox` component crashes if you are using the `virtual` option and you quickly type something such that the `Combobox` opens but no valid options are available. We already check if the current active index is available in the internal `options` list. However, if you then call `virtualizer.scrollToIndex(data.activeOptionIndex)` it will crash if you are too fast. https://github.com/user-attachments/assets/f48172e6-4098-4a31-aa16-67ce21f074d1 If you are typing slowly, then it will work as expected. https://github.com/user-attachments/assets/9d522bd5-5b54-4c12-9250-a2d92a511b35 I did find an open issue on TanStack's repo about this: https://github.com/TanStack/virtual/issues/879 This PR is basically a workaround by delaying the call. But it does have the expected behavior now. https://github.com/user-attachments/assets/2e5e47a5-b021-4897-b098-568711723b77 Fixes: #3583 --- packages/@headlessui-react/CHANGELOG.md | 1 + .../src/components/combobox/combobox.tsx | 12 +++++++++--- .../react/pages/combobox/combobox-virtualized.tsx | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md index 55e8fc2..3d0cc86 100644 --- a/packages/@headlessui-react/CHANGELOG.md +++ b/packages/@headlessui-react/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Bump `@tanstack/react-virtual` to fix warnings in React 19 projects ([#3588](https://github.com/tailwindlabs/headlessui/pull/3588)) - Fix `aria-invalid` attributes to have a valid `'true'` value ([#3639](https://github.com/tailwindlabs/headlessui/pull/3639)) - Add missing `invalid` prop to `Combobox` component ([#3677](https://github.com/tailwindlabs/headlessui/pull/3677)) +- Fix `Unexpected undefined` crash in `Combobox` component with `virtual` mode ([#3678](https://github.com/tailwindlabs/headlessui/pull/3678)) ## [2.2.0] - 2024-10-25 diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx index d0dce90..fd364bc 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.tsx @@ -479,6 +479,7 @@ function VirtualProvider(props: { children: (data: { option: unknown; open: boolean }) => React.ReactElement }) { let data = useData('VirtualProvider') + let d = useDisposables() let { options } = data.virtual! let [paddingStart, paddingEnd] = useMemo(() => { @@ -528,6 +529,7 @@ function VirtualProvider(props: { }} ref={(el) => { if (!el) { + d.dispose() return } @@ -537,9 +539,13 @@ function VirtualProvider(props: { } // Scroll to the active index - if (data.activeOptionIndex !== null && options.length > data.activeOptionIndex) { - virtualizer.scrollToIndex(data.activeOptionIndex) - } + // + // Workaround for: https://github.com/TanStack/virtual/issues/879 + d.nextFrame(() => { + if (data.activeOptionIndex !== null && options.length > data.activeOptionIndex) { + virtualizer.scrollToIndex(data.activeOptionIndex) + } + }) }} > {items.map((item) => { diff --git a/playgrounds/react/pages/combobox/combobox-virtualized.tsx b/playgrounds/react/pages/combobox/combobox-virtualized.tsx index 9873ff5..e8307ac 100644 --- a/playgrounds/react/pages/combobox/combobox-virtualized.tsx +++ b/playgrounds/react/pages/combobox/combobox-virtualized.tsx @@ -108,7 +108,7 @@ function Example({ virtual = true, data, initial }: { virtual?: boolean; data; i {({ option }) => { return ( @@ -157,7 +157,7 @@ function Example({ virtual = true, data, initial }: { virtual?: boolean; data; i {timezones.map((timezone, idx) => { return (