ui5-webcomponents icon indicating copy to clipboard operation
ui5-webcomponents copied to clipboard

WebComponent Dialog on top of OpenUI5 sap.m.Dialog cannot get focus

Open codefactor opened this issue 4 years ago • 8 comments

Bug Description

We have cases like a session timeout Dialog that is written with web component that opens when user has been idle too long. If there is an OpenUI5 Dialog under this one the OpenUI5 Dialog is "greedy" believing to be the top most modal and does not let focus go to anything else, therefore the Dialog with web components is not usable with keyboard only users if this happens.

Expected Behavior

The web component Dialog should be able to receive focus.

We had this problem with JUIC, a legacy framework, we solved it by creating a Popup instance with UI5 to wrap the JUIC modal, whenever the UI5 framework is detected. Not sure if there is any other option.

Priority

  • [ ] Low
  • [x] Medium
  • [ ] High
  • [ ] Very High

The priority indicates the severity of the issue. To set the appropriate priority consider the following criteria:

  • Breaks entire application or system - High or Very High
  • Accessibility issue - Medium or High
  • Functional issue - Medium or High
  • Visual issue - Low or Medium

Note: The priority might be re-evaluated by the issue processor.

Stakeholder Info (if applicable)

  • Organization: SuccessFactors
  • Bussiness impact: Accessibility

codefactor avatar May 29 '21 03:05 codefactor

Hello @codefactor,

Thanks for your ticket.

This is one of the major functions of dialogs. They are inert. That is, users cannot interact with content outside an active dialog window. This is according to WAI-ARIA.

You could also manage focus programmatically between open dialogs, using events and life cycle methods. Make sure you are not calling the open method with true argument as this will also prevent the initial focus.

In order to continue with processing of your request, we would highly appreciate if you could do some additional analysis of the issue. Please provide and test environment like CodeSandbox (https://codesandbox.io/s/71r1x5o51q?fontsize=14&module=%2Findex.html) or an application with steps to reproduce this problem (The processing of the issue will be faster).

We will then take closer look on whether this behavior can be improved.

Kind Regards, Dobrin

dobrinyonkov avatar May 31 '21 07:05 dobrinyonkov

We can check this and possibly extend the OpenUI5Support integration. Currently the popups collaborate on zIndex, perhaps the dialogs should be added too as this seems like a valid use case.

pskelin avatar May 31 '21 08:05 pskelin

@dobrinyonkov , As requested here is a sandbox: https://codesandbox.io/s/ui5-webcomponents-forked-9sgqn?file=/src/index.js

There is nothing we can do to programmatically manage focus here (OpenUI5 framework listens to the focus/blur events on window and detect if that event is not a child of the UI5 model and then move focus back to OpenUI5), and we are not incorrectly opening the dialog.

Please try out the above sandbox but try to use keyboard only while opening the dialog or pressing escape to close the dialogs. You will see that the UI5 dialog is greedy and does not know that the Popup from WC library is on top.

One "hacky" solution to have WC to collaborate with the OpenUI framework is to create a simple modal sap.ui.core.Popup which will enclose the Shadow Elements somehow, but only when you detect you need to do this. By doing so the sap.ui.core.Popup would then believe the WC Dialog is a new modal on top and would restrict focus to that new popup. In other words the WC dialog becomes an OpenUI5 Popup in a way, but the UI5 does not actually contribute anything visible to the Dialog.

Another suggestion might be to open a BCP ticket or email to core OpenUI5 developers to see if they have a good solution in mind for this.

codefactor avatar May 31 '21 14:05 codefactor

@ilhan007 @pskelin ,

Do you have any updates on this one?

codefactor avatar Jun 08 '21 21:06 codefactor

Here is a little hack that I did in the sandbox example to fix the issue locally for this popup:

dialog.addEventListener("afterOpen", () => {
  let popup = dialog._popup;
  if (!popup) {
    popup = dialog._popup = new sap.ui.core.Popup(
      new sap.ui.core.HTML({ content: "<div></div>" }),
      true
    );
    popup.setAutoCloseAreas([dialog]); // also called "setExtraContent" in newer versions of OpenUI5
  }
  const topLeft = sap.ui.core.Popup.Dock.LeftTop;
  popup.open(0, topLeft, topLeft, document);
  setTimeout(() => {
    dialog.applyInitialFocus();
  }, 0);
});

dialog.addEventListener("afterClose", () => {
  dialog._popup.close();
});

In short, after the Dialog is opened it will open a dummy UI5 Modal Popup with an empty div as the content, then add the Dialog web component to the "auto close areas" which as of 1.75 is now called the "extra content" (though maybe better to use auto close areas to support all versions of ui5, or perhaps just check if the setExtraContent is available and use that if it's available).

There are a few issues, though:

  1. The UI5 Popup is showing an extra block layer, It does not look like there is a way to prevent that since the Popup needs to be "modal" and according to the following line it looks like it will always show the block layer: https://github.com/SAP/openui5/blob/7e585be160fc9ccf94b2a6b157c3c711cec3feae/src/sap.ui.core/src/sap/ui/core/Popup.js#L1037 Maybe the solution is to just use the block layer from UI5 if this is being used.
  2. The apply initial focus in the setTimeout is probably not needed if the Popup in ui5-webcomponents opens the UI5 Popup first and will applyInitialFocus at the right time after the "dummy" popup has already attempted to focus
  3. I did not attempt to solve the conditionality of this, e.g. detecting that UI5 is available, assuming that the sap.ui.core.Popup/HTML controls exist already, etc. - this should be done in a more elegant way.

codefactor avatar Jun 08 '21 22:06 codefactor

When the sap.m.Dialog looses focus and it happens when ui5-dialog is being opened on top, the Popup class within OpenUI5 code checks if the focus is within the last opened sap.m.Dialog and does not recognise the ui5-dialog as such and preserves the focus, bringing back to the sap.m.Dialog, preventing the user from interacting with the ui5-dialog, which is actually on top.

Popup.prototype.onFocusEvent = function(oBrowserEvent) {
     if (this._bModal && !bContains) { 
         // case: modal popup and focus has gone somewhere else in the document
         // The popup is modal, but the focus has moved to a part of the document that is NOT inside the popup
         // check whether this modal popup is the topmost one
         
         var bTopMost = Popup.blStack.length > 0 && Popup.blStack[Popup.blStack.length - 1].popup === this;
         
         if (bTopMost) {
              // if in desktop browser or the DOM node which has the focus is input outside the popup,
              // focus on the last blurred element
      

To fully support the mixture of sap.m.Dialog and ui5-dialog, we would have to consider:

  • Focus handling - the topmost sap.m.Dialog | ui5-dialog should get the focus
  • ESC functionality - Pressing Esc should close the sap.m.Dialog | ui5-dialog instances sequentially
  • The block layer, dimming the screen would have to be reused (currently they are two)

ilhan007 avatar Jun 11 '21 14:06 ilhan007

@ilhan007 ,

I am not sure if you read my previous comment which actually provides a pretty decent solution which uses the OpenUI5 Popup itself as a placeholder then adds the Web Component Dialog itself as an "Extra Content"

Here is a fork of the sandbox I provided from before: https://codesandbox.io/s/ui5-webcomponents-forked-iip81?file=/src/index.js

This fork includes the "hack" which listens to the afterOpen/Close of the WC dialog and adds the "dummy" modal popup. If you try this out you will notice the following:

  • The Escape key works fine
  • Focus is on the WC dialog and remains there, so keyboard accessibility seems fine
  • The block layer is displayed on top of the Open UI dialog underneath

The only issue I've noticed is that I think there are actually 2 block layers, and I cannot figure out how to make the "dummy" popup in OpenUI not to display. It seems likely that the OpenUI framework cannot remove that block layer so if you encorporate this solution then you may need to disable the Block layer in the Web Component Dialog and allow the block layer from Open UI5 to take precidence.

Also, from SuccessFactors side this is going to be a priority for our release, since keyboard accessibility is a hard requirement for us. There are situations we have which have OpenUI5 dialogs that have buttons to open WC dialogs on top that exist today.

We may consider to add a solution like the one that I added in this new sandbox link from our side; however, the solution seems pretty straight forward enough to include in the WC Dialog itself.

Thanks! ~Scott

codefactor avatar Jun 14 '21 19:06 codefactor

Hi @codefactor

As discussed by mail, the Core team have suggested the usage of the data-sap-ui-integration-popup-content attribute on the web component popup.

Please let me know if that worked for you.

Regards

vladitasev avatar Mar 24 '22 12:03 vladitasev

Hello, everyone! The issue has been inactive for 21 days. If there are still questions or comments, please feel free to continue the discussion. Inactive issues will be closed after 7 days!

github-actions[bot] avatar Oct 29 '22 00:10 github-actions[bot]

Hello, everyone! The issue has been inactive for 28 days, so I am closing the issue.

github-actions[bot] avatar Nov 05 '22 00:11 github-actions[bot]