Skip to content

fix(ui): clamp menu content to available height so long lists scroll - #54391

Closed
ehealthwares wants to merge 3 commits into
anomalyco:devfrom
ehealthwares:menu-scroll-clamp
Closed

ehealthwares wants to merge 3 commits into
anomalyco:devfrom
ehealthwares:menu-scroll-clamp

Conversation

@ehealthwares

@ehealthwares ehealthwares commented Oct 10, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #54374

Type of change

  • Bug fix

What does this PR do?

The composer agent select opens upward from the footer, and the menu surface had no height constraint. corvu's popper computes the available space and publishes it as --kb-popper-content-available-height on the content element, but nothing consumed it, so a menu with more agents than fit between the footer and the top of the window rendered past the window edge and was clipped by the app: max-height: var(--kb-popper-content-available-height) plus overflow-y: auto (and overscroll-behavior: contain) on [data-component="menu-v2-content"] makes the surface clamp to that space and scroll. With the variable absent the declaration is ignored, so nothing changes for menus that are not popper-positioned.

appearance="standard" menus declare overflow: hidden, which beat the new overflow-y; that is now overflow-x: hidden, so the rounded border still clips while the vertical axis follows the base rule. select-v2 surfaces keep their own higher-specificity overflow: hidden and continue scrolling through their inner listbox, which stays capped at 12rem.

Because the focused item is inside the scroll container, the browser scrolls the current agent into view when the menu opens, so a long list no longer opens on a selection that is off-screen.

The LongList story renders a 32-item picker to reproduce and inspect the clamp.

How did you verify your code works?

Verified the compiled stylesheet against a 32-item menu in Chromium (Playwright, chromium-1217): max-height resolves to the popper's available height and overflow-y computes to auto; the panel is taller than the clamp and the wheel scrolls it; focusing a deep item scrolls it into view; select-v2 still computes hidden overflow with a 12rem scrollable listbox; without the variable max-height computes to none. Re-ran the same set for appearance="standard" (clamped, overflow-y: auto, overflow-x: hidden, last item reachable). lightningcss compiles both files without errors.

I could not run the repo's Storybook/component-test harness here (no Bun install), which is why the verification is a fixture harness rather than packages/app coverage. The bot's review comment on this PR has real before/after screenshots from the web UI built from this branch, which I did not reproduce.

Screenshots / recordings

Not attached. The reproduction screenshots (before/after from the web UI built from each checkout, showing the menu clipped at −547px on the base and capped with wheel/End-key scrolling here) are in the bot's review comment on this PR.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

The composer agent/model selects open upward, and the menu surface had no
height constraint, so a long panel rendered past the top of the window
and was clipped by the app: the agents above the cut were unreachable,
with no scrollbar and no wheel scrolling.

corvu's popper already publishes the available height as
--kb-popper-content-available-height on the content element, so clamp to
it and let the surface scroll. Without the variable the declaration is
ignored and the surface keeps its natural height. The select-v2 surfaces
override overflow back to hidden and keep their own listbox scrolling.

Adds a LongList story reproducing a 32-agent picker.

Refs anomalyco#54374
@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Oct 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran the #54374 reproduction (31 primary agents, 600px-tall window, web UI built from each checkout) against the base and this branch, and the fix works. On the base the agent menu opens 928px tall with its top at −547px, 20 of 33 agents are off-screen, and the wheel and keyboard do nothing. With this change it is capped at the popper's available height (372px, top at 9px), the wheel and End key scroll it, and the selected agent is visible when it opens. packages/ui type-checks.

Public API: unchanged (CSS and a Storybook story only).

One gap: menus with appearance="standard" keep overflow: hidden from their more specific rule. They now get the height cap but can't scroll, so long standard menus still hide items (see inline comment).

Related: #46987, #48789

Before

After

popper reports as available, so the list scrolls instead of rendering
past the window edge where it gets clipped and unreachable. */
max-height: var(--kb-popper-content-available-height);
overflow-y: auto;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works for the default compact appearance (I checked it in the composer agent menu). But [data-component="menu-v2-content"][data-appearance="standard"] further down sets overflow: hidden with higher specificity, which overrides this overflow-y. standard menus (servers registry, MCP dialog, windows titlebar menu, project view, side region) now get capped at the available height but can't scroll, so overflowing items are still unreachable. Could the standard rule use overflow-x: hidden (or drop the overflow declaration) so both appearances scroll?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 52cd8bb — the standard appearance rule now uses overflow-x: hidden so the vertical axis follows the base rule. Re-verified both appearances in Chromium (clamped, overflow-y: auto, overflow-x: hidden, last item reachable) and updated the PR description against the template.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I checked 52cd8bb: the standard rule now sets only overflow-x: hidden, so it no longer overrides the base rule's overflow-y: auto and long standard menus can scroll. That covers my comment. The LongList story's change to agent-28 also fixes the initial value I mentioned.


export const LongList = {
render: () => {
const [agent, setAgent] = createSignal("ehealthwares-marketing")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The initial value ehealthwares-marketing matches none of the generated agent-N items, so the story opens with nothing selected. Use one of the generated ids (e.g. a deep one like agent-28), so the story also shows the selected item scrolling into view.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — that was my placeholder for the story's current agent and it matched none of the generated ids, so the story opened with nothing selected (and it needlessly carried my own org name into an open-source tree). Changed to agent-28, a deep item, so the story opens with the selected agent scrolled into view.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I confirmed in the diff: LongList now starts on agent-28, so the story opens with a deep item selected.

Menu surfaces with appearance="standard" set overflow: hidden, which beat
the clamp applied to the base content rule, so long standard menus (servers
registry, MCP dialog, windows titlebar menu, project view, side region)
were capped at the available height but could not scroll — the overflow
was still unreachable.

Switch that declaration to overflow-x: hidden so the rounded border still
clips while the vertical axis follows the content rule. Also select one of
the generated ids in the LongList story so the selected agent is the one
scrolled into view.

Refs anomalyco#54374
@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Oct 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@github-actions

Copy link
Copy Markdown
Contributor

Automated PR Cleanup

Thank you for contributing to opencode.

Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions.

This PR was closed because it matched the following cleanup criteria:

  • The PR was created more than 1 month ago
  • The PR had fewer than 2 positive reactions
  • Positive reactions are counted as thumbs-up, heart, celebration, or rocket reactions on the PR

PRs created within the last month are not affected by this cleanup.

If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate.

Thanks again for taking the time to contribute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

desktop: agent select menu overflows the window with many agents — clipped instead of scrollable

1 participant