fluentui icon indicating copy to clipboard operation
fluentui copied to clipboard

[Bug]: Popover - autoSize, Arrow, overflow and scroll

Open rgcircum opened this issue 3 months ago • 9 comments

Component

Popover

Package version

9.72.3

React version

17~18

Environment

System:
    OS: Windows 11 10.0.26100
    CPU: (16) x64 Intel(R) Core(TM) Ultra 7 255H
    Memory: 4.76 GB / 31.46 GB
  Browsers:
    Chrome: 141.0.7390.123
    Edge: Chromium (141.0.3537.99)
    Firefox: 127.0 - C:\Program Files\Mozilla Firefox\firefox.exe
    Internet Explorer: 11.0.26100.1882
  npmPackages:
    @fluentui/react: ^8.125.0 => 8.125.0 
    @fluentui/react-calendar-compat: ^0.3.12 => 0.3.12
    @fluentui/react-components: ^9.72.3 => 9.72.3
    @fluentui/react-datepicker-compat: ^0.6.17 => 0.6.17
    @fluentui/react-file-type-icons: ^8.15.0 => 8.15.0
    @fluentui/react-icons-mdl2: ^1.4.0 => 1.4.0
    @fluentui/react-migration-v8-v9: ^9.9.12 => 9.9.12
    @fluentui/style-utilities: ^8.13.3 => 8.13.3
    @types/react: 17.0.45 => 17.0.45
    @types/react-dom: 17.0.17 => 17.0.17
    react: 17.0.1 => 17.0.1
    react-dom: 17.0.1 => 17.0.1

Current Behavior

If you use a popover with the autosize option and an arrow, when the scrollbar appears, the arrow is no longer visible; this is due to the overflow.

Expected Behavior

the arrow must appear

Reproduction

https://stackblitz.com/edit/jwx4z77l?file=src%2Fexample.tsx

Steps to reproduce

Drag the cursor onto the button. The popover opens. Check that there is a scroll bar within the popover. If there is a scroll bar, there is no arrow.

Are you reporting an Accessibility issue?

None

Suggested severity

Urgent - No workaround and Products/sites are affected

Products/sites affected

No response

Are you willing to submit a PR to fix?

yes

Validations

  • [x] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
  • [x] The provided reproduction is a minimal reproducible example of the bug.

rgcircum avatar Oct 31 '25 16:10 rgcircum

Hello @rgcircum

Thanks for reporting. Can confirm this is happening, it's due to styles applied in maxSize middleware, arrow is in the same container, so when the overflow is applied, arrow is not visible

mainframev avatar Nov 03 '25 00:11 mainframev

Analysis

As @mainframev mentioned, the arrow is cropped when positioning={{ autoSize: true }} is used. This occurs because the react-positioning package's maxSize middleware automatically applies overflow-x/overflow-y: auto to the popover surface element when the content exceeds the available space. Since the arrow is a direct child of the popover surface and is positioned outside its parent's boundaries (using negative offsets), the overflow property clips the arrow.

Potential Solutions

We've evaluated several approaches to address this issue:

1. Restructure the DOM (Breaking Change)

Introduce an additional wrapper element to separate the overflow container from the arrow's positioning context:

Current structure:

<PopoverSurface style={{ overflowY: 'auto' }}>
  <PopoverArrow style={{ left: '10px', bottom: '-10px' }} />
  {children}
</PopoverSurface>

Proposed structure:

<PopoverSurface> {/* No overflow - arrow positioned relative to this */}
  <PopoverArrow style={{ left: '10px', bottom: '-10px' }} />
  <PopoverContent style={{ overflowY: 'auto' }}> {/* Overflow moved here */}
    {children}
  </PopoverContent>
</PopoverSurface>

Considerations:

  • This is a breaking change that would affect the public API
  • Would require modifications to react-positioning package's middleware to target the inner content wrapper instead of the floating element
  • Could impact multiple components that rely on the current structure (Tooltip, Menu, etc.)
  • May break existing custom styling that targets the current DOM structure

2. Automatically Disable Arrow with autoSize

When both withArrow and positioning={{ autoSize: true }} are provided, automatically hide the arrow and optionally show a console warning in development mode.

Considerations:

  • Simple implementation with no breaking changes
  • Clear trade-off between features
  • May not meet user expectations if they explicitly request both features
  • Requires clear documentation about the limitation

3. Document as Known Limitation with Workaround (Recommended)

Treat this as a documented limitation and provide a workaround pattern for users who need both features.

Workaround:

<Popover withArrow positioning={{ autoSize: true }}>
  <PopoverTrigger disableButtonEnhancement>
    <Button>Trigger</Button>
  </PopoverTrigger>
  
  <PopoverSurface 
    style={{ overflowY: 'unset' }} // Override the auto overflow from middleware
    tabIndex={-1}
  >
    <div style={{ overflowY: 'auto', height: '100%' }}> // Add overflow and inherit hight from parent
      {/* Long content here */}
    </div>
  </PopoverSurface>
</Popover>

Live example: https://stackblitz.com/edit/jwx4z77l-atcdxcuy?file=src%2Fexample.tsx

Considerations:

  • No breaking changes required
  • Users who need both features have a clear, documented path forward
  • Maintains flexibility for different use cases
  • Can be implemented in userland without library changes

Recommendation

I recommend Option 3 (document as a known limitation) for the following reasons:

  1. Architectural constraints: The fundamental issue stems from CSS overflow behavior, which cannot easily be worked around without significant structural changes or trade-offs
  2. Impact scope: Options 1 and 2 would either introduce breaking changes or remove functionality for all users, even those who don't encounter this edge case
  3. Rare combination: Using autoSize with arrows is relatively uncommon, as most scrollable popovers don't need directional arrows
  4. User flexibility: The workaround gives users full control and is straightforward to implement
  5. Future compatibility: This approach doesn't prevent us from implementing a more comprehensive solution (like Option 1) in a future major version

So I'd suggest to add this limitation to the Popover documentation with the workaround example, and potentially add a development-mode console warning when both props are used together to guide users to the documentation.

dmytrokirpa avatar Nov 20 '25 11:11 dmytrokirpa

@dmytrokirpa

A breaking change doesn't seem like an option, so we're left with options 2 and 3. I don’t think we should try to render something that won't actually be visible. Ideally, we should combine both options: don't show the arrow when autoSize is enabled, and clearly document this behavior as a known limitation that will be fixed in vNext

mainframev avatar Nov 20 '25 13:11 mainframev

@dmytrokirpa

A breaking change doesn't seem like an option, so we're left with options 2 and 3. I don’t think we should try to render something that won't actually be visible. Ideally, we should combine both options: don't show the arrow when autoSize is enabled, and clearly document this behavior as a known limitation that will be fixed in vNext

I don't agree; if we choose option 2 - don’t show the arrow when autoSize is enabled - the consumer-side workaround won’t be possible. I think it’s better to add a dev warning that includes a link to the issue/explanation and a workaround example.

dmytrokirpa avatar Nov 20 '25 14:11 dmytrokirpa

@dmytrokirpa A breaking change doesn't seem like an option, so we're left with options 2 and 3. I don’t think we should try to render something that won't actually be visible. Ideally, we should combine both options: don't show the arrow when autoSize is enabled, and clearly document this behavior as a known limitation that will be fixed in vNext

I don't agree; if we choose option 2 - don’t show the arrow when autoSize is enabled - the consumer-side workaround won’t be possible. I think it’s better to add a dev warning that includes a link to the issue/explanation and a workaround example.

Yeah, I get it, they're mutually exclusive :) Another option we discussed in DMs was adding a new prop to toggle the behavior. That would avoid a breaking change, but it would also add complexity to the positioning API and to the components using it, with questionable benefit since partners probably wouldn’t use it often. Given that, option 3 is the way.

mainframev avatar Nov 20 '25 14:11 mainframev

This issue has been automatically marked as stale because it has marked as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment. Thank you for your contributions to Fluent UI!

Apparently, you're waiting for feedback. What can I say? I think the bug should be fixed now, but you don't seem willing to do it in version 9.x.x, and I don't think you ever will.

rgcircum avatar Nov 25 '25 16:11 rgcircum

Apparently, you're waiting for feedback. What can I say? I think the bug should be fixed now, but you don't seem willing to do it in version 9.x.x, and I don't think you ever will.

Hey, we're looking to fix this issue, but it seems like we'd have to make some breaking changes to do so. Since this doesn't happen often and there's a workaround available, it's not considered as urgent - no workaround available. Just let us know if the workaround works for you and if it helps sort things out. If you see a better way to solve the issue that doesn’t involve breaking changes, we’d love to chat about it!

dmytrokirpa avatar Dec 05 '25 21:12 dmytrokirpa

Thanks, the workaround works. Would you like me to close the ticket or leave it open so I don't forget to document this point?

rgcircum avatar Dec 10 '25 08:12 rgcircum