facebook / facebook/astryx

SideNavItem: support independent trailing actions without nested controls

Open
#4,987 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
13.1k
Forks
1.1k
Avg merge
1d 14h
Merged PRs (30d)
669

Description

## Problem

`SideNavItem.endContent?: ReactNode` is rendered inside the item's interactive `NavItemElement` on current main. If a consumer puts an independent action there (for example a More-menu button), the result is nested interactive markup such as ``.

The existing split-action path avoids nesting when a collapsible item also has a primary `href` or `onClick`, but it only separates the primary action from the disclosure toggle. It does not provide a seam for an arbitrary trailing action on a collapsible row whose primary row action is disclosure itself.

## Consumer case

Maka's project row needs two independently operable controls:

1. the project row toggles its child sessions;
2. a visually trailing More menu exposes project actions.

Minimal shape:

```tsx
}
>
{sessions}

```

This reproduces the nested-control problem tracked in [Maka #2360](https://github.com/Maka-Agent/maka-agent/issues/2360). The consumer-side fix is [Maka PR #2951](https://github.com/Maka-Agent/maka-agent/pull/2951).

## Cost of the consumer workaround

Maka now renders the menu as an absolutely positioned sibling outside `SideNavItem`, reserves a non-interactive placeholder in `endContent`, mirrors SideNav spacing/disclosure geometry in CSS, bridges hover/pressed paint back to the navigation button, and orders the external action before the SideNav root so keyboard focus stays adjacent to the child subtree.

That is valid and accessible, but it is coupled to private layout details (padding, gap, disclosure size) and cannot produce the ideal visual/DOM order without an upstream component seam.

## Requested capability

Please provide a supported way for a `SideNavItem` to expose an independent trailing action while keeping the row's visible surface and child disclosure behavior intact. The exact API could be an action slot, a ClickableContainer/interactive-ref composition, or an extension of the split-action path.

Acceptance properties:

- the row/disclosure target and trailing action are sibling interactive controls, never nested;
- focus order keeps both row controls adjacent and before the child group;
- Enter/Space on the row toggles disclosure, while the trailing action activates only itself;
- hover, pressed, and focus-visible treatment remains visually unified;
- layout uses SideNav-owned sizing/RTL rules rather than consumer offsets;
- both rows with children and empty rows are supported;
- `endContent` is documented as display-only if it remains inside the interactive target.

Related foundation: #3704.

Contributor guide

Open the contributing guide

Research direction

Start at the SideNavItem implementation, focusing on endContent and the existing split-action path; compare the consumer shape from Maka #2360 and PR #2951. The work is done when a supported trailing action produces sibling controls with adjacent focus order, correct keyboard behavior, unified states, SideNav-owned layout, and coverage for rows with and without children.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
accessibility, design, frontend
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.