-
Notifications
You must be signed in to change notification settings - Fork 17
WDialog
WDialog is a component for creating a dialog box. This is a floating element which forms part of the underlying form and can be used to display content in isolation from the form. A dialog is not able to be moved out of the current viewport, unlike a popup window.
A dialog may be modal which prevents the user interacting with the underlying form whilst it is open, or non-modal which does not prevent the user interacting with the underlying form.
One probably ought avoid dialogs (or, slightly less pompously: just don't OK!).
- When to use WDialog
- Creating a WDialog
- Appearance
- Accessibility
- Modal dialogs
- Dimensions
- Opening a dialog
- HTML output
- Styling WDialog
- Testing
- Known issues
- Further information
In a nutshell: pretty much never.
It is important to carefully consider the interactions which are being modelled before choosing to design with a dialog. To quote from Google:
Dialogs inform users about critical information, require users to make decisions, or encapsulate multiple tasks within a discrete process. Use dialogs sparingly because they are interruptive in nature—their sudden appearance forces users to stop their current task and refocus on the dialog content. Not every choice, setting, or detail warrants such interruption and prominence.
Alternatives to dialogs include simple menus or inline expansion within the current content area. Both approaches present information or options while maintaining the current context and are less disruptive.
When considering the use of WDialog one should be familiar with al of the [accessibility] and usability concerns this component raises. It is strongly recommended that the dialog interactions section is consulted and understood before designing a UI using a WDialog.
Dialogs can cause some accessibility and usability issues for some users and should be used with extreme caution. It should rarely or never be the first tool in a designer's armoury.
Dialogs should not be used for:
- large form segments; or
- form segments which will then create other (native) dialog-like entities such as those created during interaction with WFileWidget, WMultiFileWidget, WButton with its
cancel
state (WCancelButton
) ormessage
property (WConfirmButton
) set, or WImage in aneditable
state; or - processes which are part of the main flow of an application.
It is strongly recommended that WDialog be avoided for any application which is expected to be used on a small screen device such as a smartphone. This is due to the significant accessibility and usability issues inherent in using out-of-flow content blocks on these small screens.
WDialog has two constructors: the default constructor and a constructor which takes a WComponent argument as the dialog content - WContainer makes an excellent content container for a WDialog.
// default constructor
WDialog dialog = new WDialog();
// Constructing a WDialog with pre-existing content
WContainer container = new WContainer();
// ... do stuff with the WContainer
WDialog dialogWithContent = new WDialog(container);
Any trigger for a WAjaxControl may be used to launch a WDialog. The trigger component must be in the current view to be able to launch the dialog.
// Given WDialog dialog and AjaxTrigger trigger
dialog.setTrigger(trigger);
Note: prior to WComponents 1.2 a dialog could be opened using a specific WButton so long as it was instantiated using the (deprecated) constructor WDialog(WComponent, WButton)
or attached to the dialog using the (deprecated) method addTriggerButton(WButton)
.
A WDialog may contain almost any other WComponents with the following exceptions:
- a WDialog must not contain another WApplication as a WApplication may not contain another WApplication;
- a WDialog must not contain another WDialog as WDialogs may not be nested and any attempt to open a WDialog from the content of another WDialog will fail; and
- a WDialog may not contain a WMultiFileWidget with image editing capabilities or any WImage in an editable state as an attempt to invoke the image editor from an open WDialog will fail as the image editor uses the same dialog control frame as WDialog and this condition is not expected to change.
WDialog appears as a view-bound but floating, moveable, resizeable content container with a header, title and (usually) footer. The screenshots below show simple examples of a modal and a non-modal dialog. It is expected that a theme implementation would enhance the header, title and footer appearance but make little or no change to the rest of the dialog. See below for further details.
A WDialog will open centered in the viewport but (usually) slightly offset towards the top. The user may reposition the dialog by dragging the title bar or using keyboard shortcuts when the dialog header (or any focusable element in the header) has focus. The dialog may not be repositioned totally outside of the viewport. On narrow viewports the dialog will always be presented full-screen and is not moveable or resizeable.
Dialogs may cause accessibility problems and should be used with caution. WDialog attempts to minimise these issues but cannot ensure your dialogs are usable and accessible. The following notes summarise some of the accessibility features of WDialog and its limitations.
It should be noted that there is a specific accessibility requirement that a user must be able to close a dialog without taking any action. It is not sufficient to include a WButton in the dialog to initiate a cancel operation (though one may be included). WDialog will always provide a close button and a keyboard mapping to the ESCAPE
key which will cause the dialog to close without taking any further action. This includes not making any further calls to the application server. This is explicit in the W3C guidelines and is non-negotiable.
The WAI-ARIA guide for dialog widgets stipulates some recommended key mappings. These are applied to WDialog where possible and are all able to be implemented if the dialog content has a default WButton.
A modal dialog will attempt to prevent a user interacting with the underlying page. It is not, however, able to prevent a user interacting with the browser chrome. This may cause some usability issues when a modal dialog is open. For example the underlying page will scroll independently of the dialog content. The dialog's position is fixed (wherever the user puts it) and the content of the underlying form may scroll beneath the dialog's screen underlay. This is expected behaviour and is not a flaw in WDialog.
When a WDialog is presented in a narrow viewport it will be displayed full screen and may not be resized.
On larger viewports they may be set to a specific size or scaled to their content; in either case the user may choose to resize any WDialog. The rest of this section applies only to larger viewports.
A dialog may be resized using the ARROW
keys when the resize handle in the dialog footer has focus. The LEFT
arrow will reduce the width of the dialog, the RIGHT
arrow will increase the width of the dialog, the UP
arrow will reduce the height of the dialog and the DOWN
arrow will increase the size of the dialog. A dialog should not resize to be larger than the viewport. If a dialog is resized then the viewport reduced to a size smaller than the dialog then the dialog should resize to fill the new viewport dimensions.
The dialog will have a maximise/restore button in the dialog header. This is a toggle button. When maximised the dialog will fill the viewport.
When a WDialog is presented in a narrow viewport it will be displayed full screen and may not be moved.
On larger viewports the user may choose to move any WDialog which is not maximised by the user. A user can move a dialog by using the ARROW
keys when the dialog header has focus. The dialog will move in the direction of the ARROW
key pressed. A dialog will not move in such a way that causes its content box to be completely outside of the viewport.
When a dialog has focus the ESCAPE
key will close the dialog without taking further action as stipulated in the WAI-ARIA recommendations for the dialog widgets (modal and non-modal):
There should be a method to close the dialog without taking any action.
A dialog can be closed by clicking the close icon in the title bar or pressing the ESCAPE
key. Placing a WButton or WCancelButton in the dialog content labelled "close" is misleading as it will cause the form containing the dialog to submit to the server, not just close the dialog.
If a WButton or other trigger for a WAjaxControl is inside a dialog and the target(s) of that WAjaxControl are all in the form underlying the dialog then triggering the WButton will close the dialog then trigger the Ajax request.
If a WButton or other trigger for a WAjaxControl is inside a dialog and at least one target of that AjaxControl is also inside the dialog then the dialog will remain open and the Ajax request triggered.
The dialog's content forms part of the underlying form. The dialog is merely a positioned and styled container for that content. If a user changes a field in the dialog then that value will be returned to the server as part of the form payload. If a user interacts with a WButton, WCancelButton, WConfirmButton, WMenuItem or any item which is set to submit on change then the content of the dialog and the content of the underlying form will be submitted. If the user interacts with a WLink which does not open a pop up window then the whole page will navigate, not just the dialog content.
WInternalLink cannot be used to access specific parts of a dialog's content as the whole dialog is removed from the page flow. A link to the top of the page may cause scrolling of the underlying page but will not move the focus point to the top of the dialog content.
If a dialog has editable content then a WButton should be included in the dialog content and the content wrapper should be a WPanel. This WButton should be specified as the default submit button for the dialog content. In this way the ENTER
key will activate this default WButton if the user is interacting with a form control which allows submit on ENTER
. This is discussed in more detail in Implicit form submission.
When a dialog opens it must grab focus and place focus in the first focusable component within the dialog not within the dialog's content. When a dialog closes it must return focus to the component which had focus before the dialog opened. This is usually the trigger used to open the dialog.
A dialog will grab and maintain focus. TAB
and SHIFT + TAB
will move between focusable items inside the dialog but not allow focus to shift outside of the dialog. If the dialog is not modal the user may switch focus from the dialog to the underlying application using F6.
If a dialog contains a WAjaxControl which targets items within the dialog's content; and if the response from invoking this WAjaxControl contains a focus request then this focus request will be honoured if no other control has focus including the control which invoked the AJAX transaction.
Each dialog must have a title
which provides an adequate description of the purpose of the dialog. It is an accessibility requirement that this property be set. If the dialog title is not specified the dialog will have the title "Untitled dialog" (which may be changed within an application's internationalisation resources).
// set the dialog title to "Search"
searchDialog.setTitle("Search");
-
A WDialog with a title ("Search")
-
A WDialog without a title
WDialog may be (pseudo-)modal. This means that we make every possible attempt to ensure that the focus point stays inside the dialog and that the user is not able to interact with the underlying form. We are able to prevent access to controls in the underlying form but we are not able to prevent access to the browser chrome in all browsers. Refer to the WAI-AIA authoring practices:
// Given WDialog dialog
dialog.setModal(true);
The intitial width and height (in pixels) may be set for a WDialog. THese will determine the size of the dialog when it is opened by the user. Note that if a user resizes a WDialog this new size is retained for the life of the current view, so if the WDialog is dismissed (using the ESCAPE
key or close button) then subsequently re-opened it will be re-opened at the size previously set by the user.
The width and height will be the maximum allowed on open: the dialog will be no bigger than the viewport. On narrow viewports (such as mobile devices) WDialogs open full-screen and are not resizeable. A theme may set a minimum width and/or height for a dialog - this is not enforced in the Java API but does help prevent users from reducing the size of a dialog down to unusable levels.
The following illustration shows a WDialog with width and height set to 600. It can be seen that setting the dimensions (especially height) may cause a sub-optimal UI so these properties should be used with care.
The initial width for a dialog may be set (in pixels) using setWidth(int)
. This is the width of the dialog when it is first opened and may be adjusted by the user. If the set width
is larger than the viewport width then the initial width of the dialog will equal the viewport width. This means a dialog should never be wider than the user's screen.
If the content of the dialog is wider than this setting the dialog will not automatically resize: the content will wrap or a horizontal scroll bar may appear within the dialog depending upon the wrap point of the content. For example a wide WDropdown will cause scrolling whereas a ColumnLayout will wrap.
If width
is not set the browser will attempt to set a width appropriate to the content. This may not be possible, depending on the dialog content, therefore, it is recommended that a width usually be set, though it may be better set as a theme-level constant or percentage rather than as pixels in Java.
In narrow viewports dialogs always fill the viewport and the width
is ignored.
// with WDialog dialog
// this will set an initial width of 600px
dialog.setWidth(600);
// note that the dialog will never be wider than the viewport so
// this setting will still work if the dialog is viewed in a
// narrow viewport.
The initial height for a dialog may be set (in pixels) using setHeight(int)
. This is the height of the dialog when it is first opened and may be adjusted by the user. If the set height is larger than the larger value of the viewport height then the initial height of the dialog will equal the viewport height.
If the content of the dialog is longer than the height (or available height) a vertical scroll bar may appear within the dialog. Scrolling the dialog is independent of scrolling the underlying page.
If height
is not set the browser will attempt to set a height appropriate based on the content and this is usually feasible: it is recommended that a height is rarely set.
In narrow viewports dialogs always fill the viewport and height
is ignored.
// with WDialog dialog
// this will set an initial height of 600px
dialog.setHeight(600);
// note that the dialog will never be taller than the viewport so
// this setting will still work if the dialog is viewed in a
// short viewport.
When a dialog's content is longer than the height
(or user-set height) then the dialog content will have a scrollbar. This is independent of any page-level scroll bar. The content which is scrolled when the using the mouse wheel or similar tool for scrolling, depends upon the mouse position not the cursor point. Even if the mouse is over the dialog content the underlying page will scroll if the scroll limit of the dialog content is reached. To minimise the risk of this it is strongly recommended that a WDialog be used for small, discrete piece of data and the dialog height
property be left unset or set to a value appropriate to that content.
There are two methods of opening a dialog.
-
If the dialog has a trigger component then this component will open the dialog when activated. It is strongly recommended that a WDialog be opened in this way as it is by far the most efficient mechanism for opening a dialog. Opening a dialog from a trigger in this way is the only way to open a dialog which is guaranteed to meet accessibility requirements.
-
The dialog may be set to launch on page load using the
display()
method. This is strongly discouraged as it reduces application performance, degrades the user experience and may cause accessibility problems. In future releases of WComponents a dialog which is set to automatically open on page load may be flagged as being in an invalid state.
// given WDialog dialog
dialog.display();
If a WDialog is opened using the Java API's display()
method it is the responsibility of the application to ensure that re-visiting a view with a previously opened WDialog does not re-open that dialog. Note that it is an absolute requirement of a dialog that the user must be able to dismiss the dialog without taking any action so a WApplication cannot guarantee the open state of a WDialog which has been opened manually using the display()
method.
If the WDialog does not have a trigger component then it may automatically open on page load, however if the dialog is dismissed then it will not be able to be reopened. A dialog with a trigger component may be set to open on page load using the display()
method, obviously these dialogs will be able to be reopened if dismissed as they have a trigger.
The dialog's content is fetched using an AJAX request each time the dialog opens.
A WDialog outputs a HTML dialog element which holds the dialog content.
Any WComponent except WApplication or WDialog may be added to the content of a WDialog.
The dialog element of a WDialog is appended to the form element after all other content. Therefore whilst any component may be added to the content of a WDialog and a WDialog may be placed anywhere in the component tree. The deprecated WDialog with a launch button may not be placed in any WComponent which cannot contain interactive content.
WDialog may be styled using application specific CSS based on the dialog element or class name(s). It is strongly recommended that you avoid this and do not attempt to style the size of a dialog.
A dialog will open in the middle of the viewport but may be offset towards the top. The preferred size of the dialog may be set, this is the size of the dialog when it is first opened. All WDialogs are resizeable (except in narrow viewports). Resizing can be undertaken by dragging the resize handle in the lower right corner of the dialog or by using keyboard shortcuts whilst the resize handle has focus.
There are two aspects of WDialog's JavaScript which can be changed through configuration:
- a function name representing the size of the viewport at which all dialogs are fullscreen (property
vpUtil
default value "isPhoneLike
"); and - the vertical offset of the dialog relative to the viewport when a dialog is opened or dynamically positioned (property
offset
default0.33
).
One should note that these are configuration options for the wc/ui/dialogFrame
module which means they may also apply to WMultiFileWidget's image editor.
require(["wc/config"], function(wcconfig) {
wcconfig.set({
vpUtil: "isSmallScreen",
offset: 0.25
},"wc/ui/dialogFrame");
})
If the point at which dialogs become full screen is changed then one must change the dialog Sass (by override or exclusion) to use the same responsive action point. If, for example, the changeover point is made "isSmallScreen" using the following Javascript:
require(["wc/config"], function(wcconfig) {
wcconfig.set({
vpUtil: "isSmallScreen"
},"wc/ui/dialogFrame");
})
Then the Sass extension partial should include:
@media only screen and (max-width: 1000px) {
dialog {
height: 100%;
left: 0;
top: 0;
width: 100%;
// ... etc
}
}
This partial may be included in the theme's src/main/sass/_theme.scss
file or a file which is linked using JavaScript maodule wc/loader/style
. In the second case the partial (or file as it does not have to be a partial) would be loaded with an appropriate media query so would not need the @media
rule in Sass.
The default theme partial to include full-screen dialogs on phone-sized viewports may be omitted by overriding wc-phone.scss
or by setting either $wc-use-respond
or $wc-use-respond-dialog
to false
.
This is much simpler than changing the fullscreen changeover point as it exists only in JavaScript. The offset is the proportion of the space available above and below a dialog which is allocated to above the dialog. This is probably easier to explain by example.
- If a WDialog has a calculated height of
300px
and the viewport has a calculated height of600px
then the available space above and below the WDialog is, of course,300px
. The default offset is 0.33 this means that the top of the dialog will be placed at 99px ((0.33 * 300)px
) and the dialog will be a bit above center. - If offset is < 0.5 the dialog will be closer to the top.
- If offset > 0.5 the dialog will be closer to the bottom and will probably look a bit unfortunate.
- If the offset was set to 0.25 then the top of the dialog would be placed at 75px (
(0.25 * 300)px
) from the top of the viewport (so there would be 225px below the dialog). - If the offset was 0.5 then the top of the dialog would be positioned at 150px (
(300 * 0.5)px
) and there would be the same amount of space above and below the dialog.
One should also note the following:
- If the offset is not a number or is
<= 0
or>= 1
then the default offset will be used to stop people from being silly. - It is strongly recommended that if one really must change the offset that is should be between 0.25 and 0.5.
To set the offset:
// given a number OFFSET between 0 and 1 (exclusive)
require(["wc/config"], function(wcconfig) {
wcconfig.set({
offset: OFFSET
},"wc/ui/dialogFrame");
})
Having read that explanation vertical offset adjustment is now endangered; it seemed a good idea at the time but now I am pretty sure it is a silly idea and should be sent to Camelot.
When presented in narrow viewport, such as a mobile browser, the dialog may appear differently. Most commonly all dialogs may be rendered full screen and not allow resizing or moving so as to maximise the usability of the dialog on a small screen. See Responsive design for more information.
WDialog may be tested using com.github.bordertech.wcomponents.test.selenium.element.SeleniumWDialogWebElement
extension of org.openqa.selenium.WebElement
.
The best way to get a WDialog from a test view is by using SeleniumWComponentsWebDriver which has a method findWDialog(By)
.
- WDialog may open on page load without any indication to the user. This may cause significant accessibility and/or usability problems and should be avoided. This facility may be removed without notice.
- Some aspects of WDialog are sub-optimal in Internet Explorer, including version 11, but should still be usable and accessible and meet a reasonable standard of UI conformance in IE11.
- WDialog will not render correctly in versions of Internet Explorer older than IE11. Some attempts to ensure rendering down to IE 8 may be found in early versions of WComponents but these may need significant modification to work with the current WDialog.
- The responsive aspects of WDialog rely on both CSS and JavaScript therefore changing the point at which the dialogs become full-screen needs to be done in a Sass override and JavaScript configuration and may not be removed by disabling in-built responsive design. This latter point is due to the significant accessibility and usability problems caused by using dialogs on small screen devices - really, if one expects an application to be used on a phone (and one ought expect this) then it is probably best to avoid using WDialog at all.