JedWatson / JedWatson/react-select

Menu height not recalculated when async options load, causing truncated dropdown with menuPlacement="auto"

Open
#6,054 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

issue/bug-unconfirmed
Dominant language
TypeScript
Stars
28k
Forks
4.1k
PR merge metrics
No merged PRs in 30d

Description

Bug Description

When using react-select with async data loading and menuPlacement="auto", the dropdown menu height is calculated based on the loading state (empty or with loading indicator) and is not recalculated once the actual options load. This results in the dropdown being truncated or options being hidden below the viewport.

Image

Expected Behavior

The dropdown menu should recalculate its position and height after async options are loaded to ensure all options are visible and properly positioned.

Actual Behavior

The menu height/position is calculated once when isLoading={true} (with minimal content), and remains fixed even after options load, causing content to be cut off.

Minimal Reproduction

import Select from 'react-select';
import { useState, useEffect } from 'react';

const AsyncSelectExample = () => {
  const [options, setOptions] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    // Simulate async data loading
    setTimeout(() => {
      setOptions([
        { value: '1', label: 'Option 1' },
        { value: '2', label: 'Option 2' },
        // ... 20+ options to demonstrate the issue
      ]);
      setIsLoading(false);
    }, 2000);
  }, []);

  return (
    <div style={{ marginTop: '400px' }}> {/* Position near bottom to trigger the issue */}
      <Select
        options={options}
        isLoading={isLoading}
        menuPlacement="auto"
        placeholder="Select an option..."
      />
    </div>
  );
};

Steps to Reproduce

  1. Create a Select component with menuPlacement="auto"
  2. Position it near the bottom of the viewport
  3. Set isLoading={true} initially with empty options
  4. Load options asynchronously after a delay
  5. Open the dropdown - notice it's truncated/positioned incorrectly

Environment

  • react-select version: 5.8.3
  • React version: 18.2.0
  • Browser: Chrome v138.0.7204.101 (Official Build) (arm64)
  • OS: Mac

Workaround

I've implemented a custom hook that recalculates menu placement on menu open:

// Custom hook to handle dynamic menu placement
const useMenuPlacement = ({ maxHeight, selectRef, onMenuOpen, onMenuClose }) => {
  const [menuPlacement, setMenuPlacement] = useState('bottom');
  const [dynamicMaxHeight, setDynamicMaxHeight] = useState(maxHeight);

  const handleMenuOpen = useCallback(() => {
    // Recalculate placement based on current viewport space
    const selectElement = selectRef.current?.controlRef;
    if (selectElement) {
      const selectRect = selectElement.getBoundingClientRect();
      const spaceBelow = window.innerHeight - selectRect.bottom;
      const spaceAbove = selectRect.top;

      if (spaceBelow > 200) {
        setMenuPlacement('bottom');
        setDynamicMaxHeight(spaceBelow - 80);
      } else if (spaceAbove > 200) {
        setMenuPlacement('top');
        setDynamicMaxHeight(spaceAbove - 80);
      } else {
        setMenuPlacement(spaceBelow > spaceAbove ? 'bottom' : 'top');
        setDynamicMaxHeight(Math.max(spaceBelow, spaceAbove));
      }
    }
    onMenuOpen?.();
  }, [selectRef, onMenuOpen]);

  return {
    menuPlacement,
    dynamicMaxHeight,
    onMenuOpen: handleMenuOpen,
    // ... other returns
  };
};

Potential Solution

The issue seems to be that the menu positioning calculation happens once when the menu opens, but doesn't account for content changes. The library should:

  1. Recalculate menu placement when options change from loading to loaded state
  2. Or provide a way to trigger menu repositioning programmatically
  3. Or improve the menuPlacement="auto" logic to be more dynamic

Would be happy to contribute a PR if guidance is provided on the preferred approach.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the Select component's menuPlacement="auto" positioning path and reproduce the issue with the provided async-loading example near the bottom of the viewport. Trace when menu height and placement are calculated, then verify that loading-to-loaded options remain fully visible and correctly positioned.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.