sp-dev-docs icon indicating copy to clipboard operation
sp-dev-docs copied to clipboard

ComboBox and PeoplePicker controls are not rendering properly in SPFx when rendered inside a dialog window

Open PaoloPia opened this issue 1 year ago • 11 comments

Target SharePoint environment

SharePoint Online

What SharePoint development model, framework, SDK or API is this about?

💥 SharePoint Framework

Developer environment

None

What browser(s) / client(s) have you tested

  • [ ] 💥 Internet Explorer
  • [X] 💥 Microsoft Edge
  • [ ] 💥 Google Chrome
  • [ ] 💥 FireFox
  • [ ] 💥 Safari
  • [ ] mobile (iOS/iPadOS)
  • [ ] mobile (Android)
  • [ ] not applicable
  • [ ] other (enter in the "Additional environment details" area below)

Additional environment details

  • SPFx 1.18.2 and 1.16.1

Describe the bug / error

Starting from yesterday's afternoon (Feb 12 2024 afternoon CET) we have been experiencing rendering issues on multiple customers (4 so far) while rendering PeoplePicker and ComboBox lists of suggested values inside dialog windows of SPFx dialog framework. When you open the ComboBox to see the available values or when you type a user name to get the "Suggested People" option, the callouts render in background of the dialog and grayed out, rather than in foreground and with regular colors. As such, users cannot select values and all the SPFx customizations are broken.

image

Steps to reproduce

  1. Create a SPFx web part with a modal dialog
  2. Render a ComboBox (Fluent UI) or a People Picker (PnP Control, which internally relies on Fluent UI) inside the dialog window
  3. Try to open the ComboBox or the PeoplePicker, you will see the callout in background of the dialog

Expected behavior

Having the callout rendered properly on top of the dialog, so that users can select the suggested values. Thanks!

PaoloPia avatar Feb 13 '24 14:02 PaoloPia

Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.

ghost avatar Feb 13 '24 14:02 ghost

Which Dialog are you using? A regular HTML <dialog> perhaps.

In this case the Combobox gets added behind the dialog.

The reason for this is that both, the input and the callout are rendered in two completely different place with a z-index that will be always lower than the one of HTML Dialog.

The callout gets rendered right before the </body> and moved with CSS positioning to the <input> field.

This behaviour is the same for all Fluent UI elements that has flyouts / callouts. it's a common issue with Fluent UI which case personally me to abondon it.

It's not a bug - It's a feature with Fluent UI.

StfBauer avatar Feb 13 '24 16:02 StfBauer

Hi @StfBauer, thanks for sharing your insights. Unfortunately, the issue that I'm describing here is something that was working like charm until Monday. As such, it must be something that changed recently and I'd love to find the issue and address it, rather than moving away from Fluent UI and SPFx Dialog Framework.

PaoloPia avatar Feb 14 '24 09:02 PaoloPia

Quick update about this issue. After some investigation, we realized that it occurs when you show more than one dialog in the UI of your custom SPFx web parts or extensions. In fact, if you show one dialog just once, it works. Starting from the second dialog instance that you show, the issue occurs. You need to refresh (F5) the page to reset the behavior.

PaoloPia avatar Feb 14 '24 09:02 PaoloPia

We're looking into it. F5 is the current workaround.

AJIXuMuK avatar Feb 14 '24 17:02 AJIXuMuK

Hello, It seems to me that previously the div was rendered directly into the div and now it is rendering 2 separate divs.

Anyway, it happens both with the Dialog component and with the Modal component, and when I spent the whole day fixing it - removing the dialogs and modals / using BaseDialog + making my own styles (I was forced to because customers were concerned about this problem) and everything seemed to work, I found out that the ContextualMenu doesn't work either... image

I report even this issue at fluentUI.

I thought it might be this PR : adds a context for active descendant But it's probably not the right time when stop working.

necik11 avatar Feb 15 '24 15:02 necik11

Quick help - workaround: I had components in the Command Set that were inherited from BaseDialog as described here. That didn't work, so I created my own SPFX dialog that uses the dialog from fluentUI and not using extends BaseDialog. Everything now works as expected/before.

Here is the code:

Component:

import { Dialog, ProgressIndicator } from '@fluentui/react';
import * as React from 'react';
import * as ReactDOM from 'react-dom';

interface SPFXDialogProps {
    onClose: () => void;
    text: string;
}

// This is your custom component do whatever you want
const SPFXDialog: React.FC<SPFXDialogProps> = (props: SPFXDialogProps) => {
    return (
        <Dialog hidden={false}>
            bla bla
            <ProgressIndicator label={props.text} />
            <button onClick={props.onClose}>Close</button>
        </Dialog>
    );
};

export class SPFXDialogManager {
    // this is dialog container
    private domElement: HTMLDivElement | null = null;

    public async close(): Promise<void> {
        if (this.domElement) {
            ReactDOM.unmountComponentAtNode(this.domElement);
            this.domElement.remove();
            this.domElement = null;
        }
    }

    public async show(): Promise<void> {
        this.domElement = document.createElement('div');
        document.body.appendChild(this.domElement);

        const close = async (): Promise<void> => {
            await this.close();
        };

        const whateverYouWantPass = "";

        ReactDOM.render(
            <SPFXDialog
                onClose={close}
                text={whateverYouWantPass}
            />, this.domElement);
    }
}

Then in CA:

  public async onExecute(event: IListViewCommandSetExecuteEventParameters): Promise<void> {
  ...
    const dialogManager = new SPFXDialogManager();
    dialogManager.show().then().catch((e) => { console.log("error", e) });
    // In case you need close from here - close is public 
    dialogManager.close().then().catch((e) => { console.log("error", e) });   
  ...
  }

necik11 avatar Feb 16 '24 12:02 necik11

Hi, same problem here. Will there be any solution soon? We're evaluating if we should wait for a fix or if we need to rewrite all of our components using other ways to display a dialog. An expected timeline would help. Thanks.

cwdata avatar Feb 28 '24 08:02 cwdata