Uh oh!
There was an error while loading. Please reload this page.
Virtualize branch picker list and forward ComboboxList ref - #150
Conversation
- Add virtualized rendering and filtered item handling in `BranchToolbar` - Memoize branch-derived data and sync highlight scrolling for large branch sets - Convert `ComboboxList` to `forwardRef` to support virtualizer scroll targeting
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Virtualizer scroll element relies on fragile DOM traversal
- Forwarded the ref from ComboboxList to ScrollAreaPrimitive.Viewport via a new viewportRef prop on ScrollArea, so branchListRef.current directly references the scroll container without relying on .parentElement DOM traversal.
Or push these changes by commenting:
@cursor push 36603514fc
Preview (36603514fc)
diff --git a/apps/web/src/components/BranchToolbar.tsx b/apps/web/src/components/BranchToolbar.tsx--- a/apps/web/src/components/BranchToolbar.tsx+++ b/apps/web/src/components/BranchToolbar.tsx@@ -124,7 +124,7 @@
const branchListVirtualizer = useVirtualizer({
count: filteredBranchPickerItems.length,
estimateSize: () => 28,
- getScrollElement: () => branchListRef.current?.parentElement ?? null,+ getScrollElement: () => branchListRef.current ?? null,
overscan: 12,
enabled: isBranchMenuOpen,
});
diff --git a/apps/web/src/components/ui/combobox.tsx b/apps/web/src/components/ui/combobox.tsx--- a/apps/web/src/components/ui/combobox.tsx+++ b/apps/web/src/components/ui/combobox.tsx@@ -260,9 +260,13 @@
return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} />;
}
-function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) {+function ComboboxList({+ className,+ ref,+ ...props+}: ComboboxPrimitive.List.Props & { ref?: React.Ref<HTMLDivElement> }) {
return (
- <ScrollArea scrollbarGutter scrollFade>+ <ScrollArea scrollbarGutter scrollFade viewportRef={ref}>
<ComboboxPrimitive.List
className={cn(
"not-empty:scroll-py-1 not-empty:px-1 not-empty:py-1 in-data-has-overflow-y:pe-3",
diff --git a/apps/web/src/components/ui/scroll-area.tsx b/apps/web/src/components/ui/scroll-area.tsx--- a/apps/web/src/components/ui/scroll-area.tsx+++ b/apps/web/src/components/ui/scroll-area.tsx@@ -1,6 +1,7 @@
"use client";
import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area";
+import * as React from "react";
import { cn } from "~/lib/utils";
@@ -9,14 +10,17 @@
children,
scrollFade = false,
scrollbarGutter = false,
+ viewportRef,
...props
}: ScrollAreaPrimitive.Root.Props & {
scrollFade?: boolean;
scrollbarGutter?: boolean;
+ viewportRef?: React.Ref<HTMLDivElement> | undefined;
}) {
return (
<ScrollAreaPrimitive.Root className={cn("size-full min-h-0", className)} {...props}>
<ScrollAreaPrimitive.Viewport
+ ref={viewportRef}
className={cn(
"h-full overscroll-contain rounded-[inherit] outline-none transition-shadows focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-has-overflow-x:overscroll-x-contain",
scrollFade &&| getScrollElement: () => branchListRef.current?.parentElement ?? null, | ||
| overscan: 12, | ||
| enabled: isBranchMenuOpen, | ||
| }); |
There was a problem hiding this comment.
Virtualizer scroll element relies on fragile DOM traversal
Medium Severity
getScrollElement returns branchListRef.current?.parentElement rather than branchListRef.current itself. Because ComboboxList in combobox.tsx doesn't explicitly forward the ref to the ScrollAreaPrimitive.Viewport, the ref ends up on ComboboxPrimitive.List (the inner list element) via React 19's props-spreading behavior. The code then uses .parentElement to reach the actual scroll container. This only works because base-ui currently places {children} as a direct child of ScrollAreaPrimitive.Viewport with no intermediate wrapper. If base-ui adds a content-wrapper div inside the Viewport (a common scroll-area pattern), .parentElement will return the wrong element, silently breaking all virtualized scrolling.
Uh oh!
There was an error while loading. Please reload this page.



BranchToolbarComboboxListtoforwardRefto support virtualizer scroll targetingNote
Medium Risk
Moderate UI behavior change in a frequently used branch-selection control; virtualization/filtering and highlighted-index scrolling could introduce selection or keyboard-navigation edge cases, but no auth/data-path changes.
Overview
Improves performance of the
BranchToolbarbranch picker for large repos by virtualizing the dropdown list via TanStackuseVirtualizerand rendering rows with absolute positioning.Adds case-insensitive filtering via a new
filteredItemslist passed toCombobox, syncs highlighted-item scrolling (onItemHighlighted), and memoizes branch-derived collections (branches,branchNames,branchByName, picker items) to reduce recomputation. Also removes the unused thread error wiring.Written by Cursor Bugbot for commit 6105e44. This will update automatically on new commits. Configure here.
Note
Virtualize the BranchToolbar combobox list and forward the
ComboboxListref to support 28px row height with overscan 12 in BranchToolbar.tsxAdd list virtualization and ref forwarding to the branch picker, pre-filter items case-insensitively, and auto-scroll the highlighted index in BranchToolbar.tsx.
📍Where to Start
Start with the combobox rendering and virtualization setup in
BranchToolbarwithin BranchToolbar.tsx.Macroscope summarized 6105e44.