You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React数组Ref无法设置焦点,键盘操作下拉菜单焦点失效求助

Fixing Keyboard Navigation for Your React Dropdown Menu

Let's break down why your keyboard focus isn't switching to the dropdown menu items and fix it step by step:


1. Core Issue: Custom Component Ref Isn't Forwarded

Your MyList component is a custom component, and if it's a functional component, it won't accept refs by default. That means your listRef => (listRefs.current[index] = listRef) is actually storing undefined in the ref array—so calling .focus() on it does nothing.

Fix: Use React.forwardRef for MyList

Update your MyList component to forward the ref to its underlying DOM element (like an <li>):

const MyList = React.forwardRef((props, ref) => {
  return (
    <li ref={ref} {...props}>
      {props.children}
    </li>
  );
});

2. Keyboard Event Logic Gaps

Your current logic misses key scenarios needed for your use case:

  • Opening the menu when the button receives focus (via Tab)
  • Handling the first press of the down arrow correctly
  • Adding edge case protections for navigation boundaries

Fix: Refine the Button's Keyboard & Focus Handling

Update the MyMenuButton event handlers to cover all required keyboard interactions:

// First define your key constants (make sure these are accessible!)
const ENTER_KEY = 'Enter';
const SPACE_KEY = ' ';
const ARROW_DOWN_KEY = 'ArrowDown';
const ARROW_UP_KEY = 'ArrowUp';
const ESCAPE_KEY = 'Escape';

// Then update the button component
<MyMenuButton
  onFocus={() => {
    // Open the menu when Tab focuses the button (matches your scenario)
    setOpen(true);
    setUniqueKey(rowKey);
    setSelectedIndex(-1);
  }}
  onKeyDown={event => {
    if ([ENTER_KEY, SPACE_KEY].includes(event.key)) {
      event.preventDefault();
      setActionMenuDefaultState(event, true, !open, rowKey, -1);
    } else if (event.key === ARROW_DOWN_KEY) {
      event.preventDefault();
      if (!open) {
        // Open menu and jump directly to first item if closed
        setOpen(true);
        setUniqueKey(rowKey);
        setSelectedIndex(0);
      } else {
        // Navigate to next item, wrap around at the end
        const nextIndex = selectedIndex + 1;
        setSelectedIndex(nextIndex >= items.length ? 0 : nextIndex);
      }
    } else if (event.key === ARROW_UP_KEY) {
      event.preventDefault();
      if (open) {
        // Navigate to previous item, wrap around at the start
        const prevIndex = selectedIndex - 1;
        setSelectedIndex(prevIndex < 0 ? items.length - 1 : prevIndex);
      }
    } else if (event.key === ESCAPE_KEY) {
      event.preventDefault();
      // Close menu and return focus to the button
      setOpen(false);
      event.currentTarget.focus();
    }
  }}
/>

3. Improve Focus Sync Reliability

Your existing useEffect can fail if the ref isn't ready or the index is out of bounds. Let's harden it:

useEffect(() => {
  if (open && selectedIndex >= 0 && selectedIndex < items.length) {
    const targetItem = listRefs.current[selectedIndex];
    // Only attempt focus if the ref exists
    if (targetItem) {
      targetItem.focus();
    }
  }
}, [open, selectedIndex, items.length]);

4. Add Blur Handling for Menu Closure

To match standard keyboard navigation behavior, close the menu when it loses focus (e.g., user Tabs away from the menu):

<MyDivWrapper
  onBlur={(e) => {
    // Only close if focus moves outside the menu container
    if (!e.currentTarget.contains(e.relatedTarget)) {
      setOpen(false);
      setSelectedIndex(-1);
    }
  }}
>
  {items.map((item, index) => {
    return (
      <MyList
        ref={listRef => (listRefs.current[index] = listRef)}
        key={rowKey + index}
        onKeyDown={event => {
          console.log("Able to focus and enter");
        }}
      >
        <p>Download</p>
      </MyList>
    );
  })}
</MyDivWrapper>

These changes should resolve your focus issue: refs will correctly target DOM elements, keyboard interactions will handle all edge cases, and focus will sync properly between the button and menu items.

内容的提问来源于stack exchange,提问作者kenpeter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:17:19