diff --git a/superset-frontend/packages/superset-ui-core/src/components/Select/Select.test.tsx b/superset-frontend/packages/superset-ui-core/src/components/Select/Select.test.tsx
index 93608a5031a..e13c98c5473 100644
--- a/superset-frontend/packages/superset-ui-core/src/components/Select/Select.test.tsx
+++ b/superset-frontend/packages/superset-ui-core/src/components/Select/Select.test.tsx
@@ -779,6 +779,38 @@ test('Renders only an overflow tag if dropdown is open in oneLine mode', async (
expect(withinSelector.getByText('+ 2 ...')).toBeVisible();
});
+// Test for checking the issue described in: https://github.com/apache/superset/issues/35132
+test('Maintains stable maxTagCount to prevent click target disappearing in oneLine mode', async () => {
+ render(
+ ,
+ );
+
+ const withinSelector = within(getElementByClassName('.ant-select-selector'));
+ expect(withinSelector.getByText(OPTIONS[0].label)).toBeVisible();
+ expect(withinSelector.getByText('+ 2 ...')).toBeVisible();
+
+ await userEvent.click(getSelect());
+ expect(withinSelector.getByText(OPTIONS[0].label)).toBeVisible();
+
+ await waitFor(() => {
+ expect(
+ withinSelector.queryByText(OPTIONS[0].label),
+ ).not.toBeInTheDocument();
+ expect(withinSelector.getByText('+ 3 ...')).toBeVisible();
+ });
+
+ // Close dropdown
+ await type('{esc}');
+
+ expect(await withinSelector.findByText(OPTIONS[0].label)).toBeVisible();
+ expect(withinSelector.getByText('+ 2 ...')).toBeVisible();
+});
+
test('does not render "Select all" when there are 0 or 1 options', async () => {
const { rerender } = render(
,
diff --git a/superset-frontend/packages/superset-ui-core/src/components/Select/Select.tsx b/superset-frontend/packages/superset-ui-core/src/components/Select/Select.tsx
index bf8c99263d4..e8300f6eb39 100644
--- a/superset-frontend/packages/superset-ui-core/src/components/Select/Select.tsx
+++ b/superset-frontend/packages/superset-ui-core/src/components/Select/Select.tsx
@@ -24,6 +24,7 @@ import {
useMemo,
useState,
useCallback,
+ useRef,
ClipboardEvent,
Ref,
ReactElement,
@@ -143,6 +144,32 @@ const Select = forwardRef(
: 1
: (propsMaxTagCount ?? MAX_TAG_COUNT);
+ // Prevent maxTagCount change during click events to avoid click target disappearing
+ const [stableMaxTagCount, setStableMaxTagCount] = useState(maxTagCount);
+ const isOpeningRef = useRef(false);
+
+ useEffect(() => {
+ if (oneLine) {
+ if (isDropdownVisible && !isOpeningRef.current) {
+ // Mark that we're in the opening process
+ isOpeningRef.current = true;
+ // Use requestAnimationFrame to ensure DOM has settled after the click
+ requestAnimationFrame(() => {
+ setStableMaxTagCount(0);
+ isOpeningRef.current = false;
+ });
+ return;
+ }
+ if (!isDropdownVisible) {
+ // When closing, immediately show the first tag
+ setStableMaxTagCount(1);
+ isOpeningRef.current = false;
+ }
+ return;
+ }
+ setStableMaxTagCount(maxTagCount);
+ }, [maxTagCount, isDropdownVisible, oneLine]);
+
const mappedMode = isSingleMode ? undefined : 'multiple';
const sortSelectedFirst = useCallback(
@@ -599,16 +626,16 @@ const Select = forwardRef(
const omittedCount = useMemo(() => {
const num_selected = ensureIsArray(selectValue).length;
- const num_shown = maxTagCount as number;
+ const num_shown = stableMaxTagCount as number;
return num_selected - num_shown - (selectAllMode ? 1 : 0);
- }, [maxTagCount, selectAllMode, selectValue]);
+ }, [stableMaxTagCount, selectAllMode, selectValue]);
const customMaxTagPlaceholder = () =>
`+ ${omittedCount > 0 ? omittedCount : 1} ...`;
// We can't remove the + tag so when Select All
// is the only item omitted, we subtract one from maxTagCount
- let actualMaxTagCount = maxTagCount;
+ let actualMaxTagCount = stableMaxTagCount;
if (
actualMaxTagCount !== 'responsive' &&
omittedCount === 0 &&