Skip to content

fix(context-menu): position anchor in a way which escape containers COMPASS-9673 #7192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

kraenhansen
Copy link
Contributor

@kraenhansen kraenhansen commented Aug 12, 2025

Description

When embedded as the data-explorer, the right click menu is rendered inside a container with position: relative;.
When the context menu anchor is positioned absolute, it will be relative to that container.

Merging this PR will:

  • Update the anchor to be positioned "fixed":

    If the position property is fixed, the containing block is established by the viewport (in the case of continuous media) or the page area (in the case of paged media).

I tested this locally by modifying the compass-web sandbox to reproduce the bug and update the code to fix it.
I pushes a commit with the change I did to the sandbox and verified using the "compass-web" sandbox as well as "compass".

Checklist

  • New tests and/or benchmarks are included
  • Documentation is changed or added
  • If this change updates the UI, screenshots/videos are added and a design review is requested
  • I have signed the MongoDB Contributor License Agreement (https://www.mongodb.com/legal/contributor-agreement)

Motivation and Context

  • Bugfix
  • New feature
  • Dependency update
  • Misc

Open Questions

Dependents

Types of changes

  • Backport Needed
  • Patch (non-breaking change which fixes an issue)
  • Minor (non-breaking change which adds functionality)
  • Major (fix or feature that would cause existing functionality to change)

@kraenhansen kraenhansen self-assigned this Aug 12, 2025
@Copilot Copilot AI review requested due to automatic review settings August 12, 2025 14:39
@kraenhansen kraenhansen requested a review from a team as a code owner August 12, 2025 14:39
@github-actions github-actions bot added the fix label Aug 12, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes a positioning issue in the context menu component when it's embedded within containers that have position: relative. The fix changes the anchor positioning from absolute to fixed to ensure the context menu is positioned relative to the viewport rather than the containing element.

  • Changes context menu anchor positioning from absolute to fixed

@kraenhansen kraenhansen added the no release notes Fix or feature not for release notes label Aug 12, 2025
@gribnoysup
Copy link
Collaborator

I tested this locally by modifying the compass-web sandbox to reproduce the bug and update the code to fix it.

I think we discussed this on the standup, do you mind commiting this code also so that we have an environment that's a bit closer to mms?

@kraenhansen kraenhansen force-pushed the kh/context-menu-fixed-position branch from 1bc2235 to c436d82 Compare August 18, 2025 13:17
}
#container {
--offset: 30px;
position: absolute;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Using position absolute and having an offset in every direction ensures any position: relative; contained will resolve its position relative to this with the offset, triggering the original issue.

@@ -62,18 +64,16 @@ export function ContextMenuProvider({
);

useEffect(() => {
// Don't set up event listeners if we have a parent context
if (parentContext || disabled) return;
// We skip registering listeners when parentContext is known to avoid registering multiple (nested) listeners
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Drive-by to have the comment say something about, why we're actually doing this.

@@ -86,7 +94,7 @@ export function ContextMenu({
data-testid="context-menu-anchor"
ref={anchorRef}
style={{
position: 'absolute',
position: 'fixed',
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The actual fix for the original bug.

@@ -17,6 +17,10 @@ export type {
ContextMenuItemGroup,
} from '@mongodb-js/compass-context-menu';

const containerStyles = css({
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This container is not just a part of the provider from the compass-context-menu package, because we need access to the css helper, which would introduce a circular dependency.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This probably should be display: contents so that it doesn't create its own box and allows parent and children to keep their styles without the need to account for this extra element (we do something pretty similar here).

Also if this belongs to the context-menu rather than to compass-components, it should probably stay there, you can inline styles with a style property to avoid the dependency, although ContextMenuProviderBase being configurable like that also looks good to me. I would rather pass the ref directly maybe, this seems to be a more common pattern that I see in these cases, but no strong preference for that, local state keeping the value around is also okay.

Copy link
Contributor Author

@kraenhansen kraenhansen Aug 20, 2025

Choose a reason for hiding this comment

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

This probably should be display: contents

Great idea - thanks for pointing to that.

if this belongs to the context-menu rather than to compass-components, it should probably stay there

This was mostly to avoid inline styling, so I agree this could live in the context menu package, when it's just a display: contents.

@kraenhansen kraenhansen requested a review from gribnoysup August 18, 2025 13:21
@kraenhansen kraenhansen force-pushed the kh/context-menu-fixed-position branch from ceb1200 to d886c3a Compare August 20, 2025 08:04
@kraenhansen kraenhansen force-pushed the kh/context-menu-fixed-position branch from d886c3a to 332bfe0 Compare August 20, 2025 08:13
@kraenhansen
Copy link
Contributor Author

kraenhansen commented Aug 20, 2025

For some reason, this test is failing:

it('should render the close tab button hidden', async function () {
expect(
getComputedStyle(await screen.findByLabelText('Close Tab'))
).to.have.property('display', 'none');
});

It doesn't fail when I run it in isolation (using .only) and there's not difference in the DOM tree when I add a screen.debug() as the first line of that test, between running all test (and failing) and with only (and succeeding).

Also tried changing this to (without luck - still failing when all tests are ran):

const element = await screen.findByLabelText('Close Tab');
expect(element).to.not.be.visible;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug fix no release notes Fix or feature not for release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants