Support (or document) `trigger="contextMenu"` on collection items (GridListItem / TreeItem / Row)

Abierto
#10,444 1 comentario 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
52/100
Tipo de issue
Nueva funcionalidad
Claridad
Bastante claro
Estado de actividad
Tranquilo
Stack tecnológico
react, typescript

Línea de trabajo

Empieza por useContextMenu y MenuTrigger; después, compara el manejo de eventos de collection-item en useSelectableItem.ts:409 y usePress.ts:112/1010. Inspecciona las stories y pruebas de Menu mencionadas en el issue para determinar si el resultado admitido es documentación o un cambio de API. La tarea estará terminada cuando una fila de la collection tenga un flujo de menú contextual compatible, sin advertencias, con comportamiento documentado y cobertura.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Provide a general summary of the feature here

trigger="contextMenu" (new in v1.20.0) works well for a standalone trigger, but there doesn't appear to be a supported way to use it on a collection item — a GridListItem, TreeItem, or table Row. Right-clicking a row to open the same menu its kebab button opens seems like one of the most common reasons to want a context menu, so I suspect this is either a gap or a pattern I've failed to find.

Either a supported API for it, or docs guidance on the intended approach, would help.

🤔 Expected Behavior?

Being able to attach a context menu to a collection item, so that right-click / long-press / Shift+F10 on a row opens the same menu the row's kebab button opens.

Collection items already look like valid trigger candidates: the docs say MenuTrigger "works with any pressable React Aria component", and rows are pressable —

  • useGridListItem → useSelectableItem → usePress (useSelectableItem.ts:409)
  • usePress reads PressResponderContext (usePress.ts:112) and merges the remaining DOM props into its result (usePress.ts:1010)

so a row would consume MenuTrigger's onContextMenu / onKeyDown correctly if it could receive them.

😯 Current Behavior

1. MenuTrigger can't wrap a collection item. MenuTrigger must render as an ancestor of its trigger, but inside a collection it hits the useIsHidden guard and returns null during the collection-building pass, so the item never registers. Wrapping a TreeItem removes every row from the tree — the collection renders empty.

2. Wrapping the row's content in <Pressable> works, but warns once per row. The Pressable child ends up being a div with no interactive ARIA role. The row itself is role="row" (RAC's Tree is a treegrid), which isn't in Pressable's allowed-role list, so there's nothing valid to put the role on:

<Pressable> child must have an interactive ARIA role.

Adding excludeFromTabOrder just swaps it for the other warning:

<Pressable> child must be focusable. Please ensure the tabIndex prop is passed through.

Putting a fake interactive role on a div inside a treegrid row seems worse than the warning, so neither option feels right.

3. Every example uses a standalone <Button>. packages/react-aria-components/stories/Menu.stories.tsx:532, packages/@react-spectrum/s2/stories/Menu.stories.tsx:409, and packages/react-aria-components/test/Menu.test.tsx:652 / :701, plus both docs sites. As a side note, the docs example makes a non-interactive 250×150 region into a <button> purely to satisfy the pressable requirement — it's announced as a button but does nothing when pressed, which reads a little odd as the canonical example.

💁 Possible Solution

useContextMenu works today and looks like the intended escape hatch — contextMenuProps spread straight onto a TreeItem / GridListItem keeps all the platform handling, with no wrapper and no warnings. If that's the recommended pattern for collections, documenting it on the Menu page (or on GridList / Tree / Table) would settle it.

The one thing it loses versus MenuTrigger is positioning the menu at the pointer, which needs getTargetRect — that isn't part of Popover's public types, so it currently needs a @ts-expect-error. Exposing it, or otherwise providing a supported way to anchor a popover to a point, would close that gap.

🔦 Context

We have a collections sidebar built on Tree, where each row has a kebab menu (rename, share, delete, …). We wanted right-click on the row to open that same menu, keeping the kebab button as-is. The kebab stays either way — the context menu is an addition, not a replacement.

We landed on <Pressable> around the row content, which works, but it restructures the row purely to host the trigger and logs a warning per row in development, so it doesn't feel like the intended shape.

💻 Examples

Wrapping the item — collection renders empty:

// Every row disappears: MenuTrigger returns null during the collection build,
// so no TreeItem is ever registered.
<Tree aria-label="Collections">
  <MenuTrigger trigger="contextMenu">
    <TreeItem textValue="Design">
      <TreeItemContent>Design</TreeItemContent>
    </TreeItem>
    <Popover>
      <Menu>
        <MenuItem>Rename…</MenuItem>
        <MenuItem>Delete…</MenuItem>
      </Menu>
    </Popover>
  </MenuTrigger>
</Tree>

Wrapping the content — works, but warns once per row:

<TreeItem textValue="Design">
  <TreeItemContent>
    <MenuTrigger trigger="contextMenu">
      {/* warns: child must have an interactive ARIA role */}
      <Pressable><div className="row-content">Design</div></Pressable>
      <Popover>
        <Menu>
          <MenuItem>Rename…</MenuItem>
          <MenuItem>Delete…</MenuItem>
        </Menu>
      </Popover>
    </MenuTrigger>
  </TreeItemContent>
</TreeItem>

Possibly related: #7197 (pass onContextMenu in RAC Tab), #7987 (useLongPress with a Table Row — event and labelling props get filtered out), #9863 (right-click a table row containing a link).

Versions: [email protected], [email protected], [email protected], React 19.

🧢 Your Company/Team

Metaview

Lenguaje dominante
TypeScript
Estrellas
16k
Forks
1.6k
Merge medio
2 d 17 h
PR fusionados (30 d)
41

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de adobe/react-spectrum

Todos los issues de adobe/react-spectrum

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.