A Flyout is used to show and hide additional information and content that is related to the main page without navigating or routing to a new page.
Usage
When to use
- When displaying additional information, context, or details that extend or enhance an object or element on the main page.
- To present functions that are secondary to the main page or user flow.
- To preview content without navigating or routing to a new page.
When not to use
- When requesting information or feedback from the user through a form. Instead, use a Modal or consider moving the content to its own page.
- When displaying overly complex information, consider moving the content to its own page.
Flyout vs Modal
While similar in functionality and interaction, the Flyout and Modal are meant to be used in different scenarios and to express different types of content. There is a fair amount of overlap in their usage but they differ in complexity, status and messaging, speed and regularity, and experience hierarchy.
Complexity
A Flyout is useful for more complex content, given the space it occupies in the viewport, while Modals are useful for less complex content that can be interacted with quickly.
Status and messaging
Flyouts are useful when displaying detailed content that relates to the page, while Modals are useful for messaging status, e.g., confirming a destructive action or warning about the effects of a change.
Speed and regularity
Modals are better suited for quick interactions that occur infrequently, while Flyouts, due to their support for more complex content, can occupy more of the users’ time and be recalled more frequently.
Experience hierarchy
While each of these components is triggered by a user action, where they exist in the flow is fundamentally different:
- A Modal blocks the user from progressing further in the main flow (Fig 1.0), forcing them to take action or make a decision.
- A Flyout extends or "branches" off from the main flow to add detail and highlight secondary features and functions (Fig 1.1).
- Rather than blocking the user from continuing in the main flow, a Flyout enhances and adds detail to the flow to aid in the completion of a function.
Fig. 1.0: Hierarchy representation of a Modal blocking the user progression through a flow.
Fig. 1.1: Hierarchy representation of the Flyout relative to the user flow.
Usage examples
Preview content
Previewing read-only content is an ideal use case for a Flyout as it keeps the user in the context of the current flow while detailing additional secondary information.
Use a Flyout as a detailed preview of an object on the main page.
Code snippets and examples
While code snippets and terminal scripts are usually detailed, they are well suited content within a Flyout due to their contextual relevancy to the content on the page, while maybe not being complex enough to exist on their own page.
Forms
Don't use a form in a Flyout, whether the function is creating an object, or updating an existing one. This type of content is often complex and more appropriate on its own page, or in the case of a simple form, within a Modal.
Size
The available sizes are medium (default) and large.
Best practices
- Use a Flyout size that best accounts for the complexity and detail of the content.
- The medium size accounts for the majority of scenarios and is the default recommended size.
Flyout header
The Flyout header features several properties to better communicate the purpose and content within the component.
Title icon
With title icon
Without title icon
Usage
An icon paired with the title can help reinforce the purpose and function of the Flyout while also drawing the eye to the header and title area.
The purpose and function of the Flyout should not rely solely on an icon, instead the title should be explicit and pragmatic while the icon provides visual support.
Tagline
With tagline
With tagline and icon
A tagline helps the user maintain the context of the main page the Flyout was triggered from. Since a Flyout disables and obscures the main page content, adding a tagline can help the user understand the relationship between the Flyout and the main page.
The tagline should directly reference the page, feature title, or object to reinforce the purpose of the Flyout.
Description
A description provides additional information about the Flyout.
With description
With description and icon
Flyout body
The body of the Flyout supports any generic content, local components, or Helios components via an instance swap property (genericInstance
) in Figma. In code, yield
is supported.
Flyout footer
The Flyout footer is a persistent content area at the bottom of the Flyout, and supports additional descriptive content, links, actions, and any other generic content or Helios components.
The Ember and Figma components account for the footer in slightly different ways, though both can achieve the same results:
- The Ember component is a generic container that yields elements passed to it.
- The Figma component consists of a variant for the number of actions, as well as support for generic content via an instance swap property.
With one action
With two actions
For more guidance and details around organizing buttons and actions, refer to the Button organization pattern documentation.
Actions
A Flyout supports actions within the footer allowing for basic functions to be performed. This usage should be limited to performing secondary functions that are related to the main page to help the user maintain context in the primary flow. Some examples of this are:
- Batch updating and creating relationships between one or more objects
- Linking to external resources using a link that appears as a button
Use a Flyout for actions like batch selection that are secondary to the main page.
Use a Flyout for simple declarative content like text and links that enhance the main page.
Don't use a Flyout for editing or creating objects. These are generally considered primary functions and should be handled on their own page or within a Modal in simple scenarios.
Dismissal
The primary dismissal method for the Flyout is the dismiss action in the header. The Flyout does not support action buttons to “confirm” or “cancel” the Flyout as the component is not intended to perform functions.
Multiple dismissal options are available that can be customized in production with a callback (on onClose
, or onOpen
) function:
- Dismiss button in the header
- Clicking with a mouse outside of the Flyout on the main page
- Hitting the escape (
ESC
) key on a keyboard
Positioning and responsive sizing
A Flyout should slide out from the right side of the viewport on top of the main page content and occupy 100% of the viewport height.
- This is true regardless of whether there is a sidebar or navigational element that persists on the page.
- A Flyout should overlay all content and block/disable interaction on the main page.
On smaller viewports, the Flyout should occupy 100% of the viewport width minus half the size of the minimized SideNav width from the viewport edge.
- If the body content of the Flyout exceeds the maximum height of the viewport, a scroll will be introduced.
- The Flyout header is not included in the scrolling section, only the body content. The header should always be visible to help the user understand the Flyout content and how it relates to the main page.
- The Flyout should not be resized manually, rather select the size that best accommodates the content.
Browser support
The Flyout component leverages the <dialog>
element which is currently supported by all major browser vendors.
Page scroll
When a Flyout is open, the rest of the page becomes inert. The page scrolling is also disabled by applying overflow: hidden
to the <body>
element, to make it clear to the user that the underlying elements are not interactive and to avoid confusion. Depending on users’ scroll bar settings, opening a Flyout may cause slight layout shifts on the horizontal axis.
Positioning
As an overlaying component, the Hds::Flyout
is rendered on the top layer, meaning it is always placed on top of all other elements in the page.
Focus trap
This component uses ember-focus-trap
to prevent the focus from going outside the Flyout and to deactivate the Flyout when clicking outside. This Ember modifier requires at least one interactive element to be present within the Flyout, which is by default achieved by the dismiss button in the header.
Focus and focus trap
This component uses ember-focus-trap
to prevent the focus from going outside the Flyout and to dismiss the Flyout when clicking outside the Flyout. This Ember modifier requires at least one interactive element to be present within the Modal, which is by default achieved by the dismiss button in the header.
When a Modal is opened with the keyboard, the focus is automatically set to the first focusable element inside the Modal, which is the “Dismiss” button. The action of this button has no effect on the system, so focusing on it helps prevent users from accidentally confirming the Modal.
When the Flyout has been closed, the browser automatically returns the focus to the element that initiated the opening. If that element doesn't exist anymore in the DOM (e.g., if the Flyout is opened using an Interaction item in a Dropdown) the focus is returned to the <body>
element. To avoid this side-effect (that comes with accessibility implications), it's possible to use the @returnFocusTo
argument, where the consumer can provide the DOM id
attribute of the element where the focus should be returned once the Flyout is closed.
How to use this component
<Hds::Button
@text="Open Flyout"
@color="secondary"
{{on "click" (fn this.activateFlyout "basicFlyoutActive")}}
/>
{{#if this.basicFlyoutActive}}
<Hds::Flyout id="basic-flyout"
@onClose={{fn this.deactivateFlyout "basicFlyoutActive"}} as |M|>
<M.Header @tagline="Main page context" @icon="info">
Additional information
</M.Header>
<M.Description>
Lorem ipsum dolor sit amet consectetur.
Ut ultrices id venenatis in felis auctor ante.
</M.Description>
<M.Body>
<p class="hds-typography-body-300 hds-foreground-primary">
Aliquam ac enim iaculis, faucibus enim id, dapibus quam.
Nunc nibh mi, vehicula sed enim eget, lacinia venenatis tortor.
Quisque vitae accumsan est, eu vehicula arcu.
</p>
</M.Body>
</Hds::Flyout>
{{/if}}
Component API
Flyout
<[F].Header>
yielded component
DialogPrimitive::Header
yielded as contextual component (see below).
<[F].Description>
yielded component
DialogPrimitive::Header
yielded as contextual component (see below).
<[F].Body>
yielded component
DialogPrimitive::Header
yielded as contextual component (see below).
<[F].Footer>
yielded component
DialogPrimitive::Header
yielded as contextual component (see below).
size
enum
- medium (default)
- large
returnFocusTo
string
id
of the element where the focus should be returned once the flyout is closed (e.g., if the element that initiated the event is not in the DOM anymore once closed).
onOpen
function
onClose
function
…attributes
...attributes
.
Contextual components
[F].Header
The DialogPrimitive::Header
component, yielded as contextual component.
DialogPrimitive::Header
component.
[F].Description
The DialogPrimitive::Description
component, yielded as contextual component.
DialogPrimitive::Description
component.
[F].Body
The DialogPrimitive::Body
component, yielded as contextual component.
DialogPrimitive::Body
component.
[F].Footer
The DialogPrimitive::Footer
component, yielded as contextual component.
DialogPrimitive::Footer
component.
Anatomy
Element | Usage |
---|---|
TitleIcon | Optional |
Description | Optional |
Tagline | Optional |
Title | Required |
Dismiss button | Required |
Body | Required; accepts any custom component instance (local or from Helios) |
Footer | Optional |
Actions | Optional; either none, one, two, or three |
Custom Content | Optional; accepts any custom component instance (local or from Helios) |
Conformance
The Flyout component is conformant when used as directed.
Focus
When a Flyout is triggered, focus is trapped within the component. The dismiss button should receive focus as the first interactive element in the DOM (document object model).
Applicable WCAG Success Criteria
This section is for reference only, some descriptions have been truncated for brevity. This component intends to conform to the following WCAG Success Criteria:
-
1.1.1
Non-text Content (Level A):
All non-text content that is presented to the user has a text alternative that serves the equivalent purpose. -
1.3.1
Info and Relationships (Level A):
Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. -
1.3.2
Meaningful Sequence (Level A):
When the sequence in which content is presented affects its meaning, a correct reading sequence can be programmatically determined. -
1.3.3
Sensory Characteristics (Level A):
Instructions provided for understanding and operating content do not rely solely on sensory characteristics of components such as shape, color, size, visual location, orientation, or sound. -
1.3.5
Identify Input Purpose (Level AA):
The purpose of each input field collecting information about the user can be programmatically determined when the input field serves a purpose identified in the Input Purposes for User Interface Components section; and the content is implemented using technologies with support for identifying the expected meaning for form input data. -
1.4.1
Use of Color (Level A):
Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element. -
1.4.10
Reflow (Level AA):
Content can be presented without loss of information or functionality, and without requiring scrolling in two dimensions. -
1.4.11
Non-text Contrast (Level AA):
The visual presentation of the following have a contrast ratio of at least 3:1 against adjacent color(s): user interface components; graphical objects. -
1.4.12
Text Spacing (Level AA):
No loss of content or functionality occurs by setting all of the following and by changing no other style property: line height set to 1.5; spacing following paragraphs set to at least 2x the font size; letter-spacing set at least 0.12x of the font size, word spacing set to at least 0.16 times the font size. -
1.4.13
Content on Hover or Focus (Level AA):
Where receiving and then removing pointer hover or keyboard focus triggers additional content to become visible and then hidden, the following are true: dismissible, hoverable, persistent (see link). -
1.4.3
Minimum Contrast (Level AA):
The visual presentation of text and images of text has a contrast ratio of at least 4.5:1 -
1.4.4
Resize Text (Level AA):
Except for captions and images of text, text can be resized without assistive technology up to 200 percent without loss of content or functionality. -
1.4.5
Images of Text (Level AA):
This is old. Don’t do this. Use text. Also a logo is not an image of text, so that’s fine. -
2.1.1
Keyboard (Level A):
All functionality of the content is operable through a keyboard interface. -
2.1.2
No Keyboard Trap (Level A):
If keyboard focus can be moved to a component of the page using a keyboard interface, then focus can be moved away from that component using only a keyboard interface. -
2.1.4
Character Key Shortcuts (Level A):
If a keyboard shortcut is implemented in content using only letter (including upper- and lower-case letters), punctuation, number, or symbol characters, then it should be able to be turned off, remapped, or active only on focus. -
2.4.2
Page Titled (Level A):
Web pages have titles that describe topic or purpose. -
2.4.3
Focus Order (Level A):
If a Web page can be navigated sequentially and the navigation sequences affect meaning or operation, focusable components receive focus in an order that preserves meaning and operability. -
2.4.6
Headings and Labels (Level AA):
Headings and labels describe topic or purpose. -
2.4.7
Focus Visible (Level AA):
Any keyboard operable user interface has a mode of operation where the keyboard focus indicator is visible. -
3.2.1
On Focus (Level A):
When any user interface component receives focus, it does not initiate a change of context. -
3.2.2
On Input (Level A):
Changing the setting of any user interface component does not automatically cause a change of context unless the user has been advised of the behavior before using the component. -
3.3.1
Error Identification (Level A):
If an input error is automatically detected, the item that is in error is identified and the error is described to the user in text. -
3.3.2
Labels or Instructions (Level A):
Labels or instructions are provided when content requires user input. -
3.3.3
Error Suggestion (Level AA):
If an input error is automatically detected and suggestions for correction are known, then the suggestions are provided to the user, unless it would jeopardize the security or purpose of the content. -
3.3.4
Error Prevention (Legal, Financial, Data) (Level AA):
For Web pages that cause legal commitments or financial transactions for the user to occur, that modify or delete user-controllable data in data storage systems, or that submit user test responses, at least one of the following is true: submissions are reversible, data is checked and user is provided an opportunity to correct them, a mechanism is available for reviewing, confirming and correcting the information before finalizing the submission. -
4.1.2
Name, Role, Value (Level A):
For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to user agents, including assistive technologies. -
4.1.3
Status Messages (Level AA):
In content implemented using markup languages, status messages can be programmatically determined through role or properties such that they can be presented to the user by assistive technologies without receiving focus.
Support
If any accessibility issues have been found within this component, let us know by submitting an issue.
4.15.0
Updated
Aligned private class properties to follow a standardized notation
4.13.0
Updated
Added returnFocusTo
argument to control where the browser focus is returned once the flyout is closed
Removed isDismissDisabled
from signature (not an actual argument)
4.12.0
Updated
Fixed issue with box-sizing
inheritance due to a all: unset
CSS rule applied to the DialogPrimitive
subcomponent
4.10.0
Updated
Flyout.Header
Changed the HTML element wrapping the tagline and title from a <div>
to a <h1>
. If you have a heading HTML tag inside the header yield block, either remove it or change it to a <span>
.
4.7.0
Deprecated
In this version, the Flyout sub-components have been deprecated and replaced with the equivalent DialogPrimitive sub-components (shared also with the Modal component). The deprecated Flyout sub-components will be removed in the next major release.
To do the migration, if you use the <Hds::Flyout::***>
invocation:
Deprecated: | Replace with: |
---|---|
Flyout::Header |
DialogPrimitive::Header |
Flyout::Description |
DialogPrimitive::Description |
Flyout::Body |
DialogPrimitive::Body |
Flyout::Footer |
DialogPrimitive::Footer |
If instead you use the (component hds/flyout/***)
:
Deprecated: | Replace with: |
---|---|
hds/flyout/header |
hds/dialogprimitive/header |
hds/flyout/description |
hds/dialogprimitive/description |
hds/flyout/body |
hds/dialogprimitive/body |
hds/flyout/footer |
hds/dialogprimitive/footer |
In the refactoring, we have been able to maintain existing CSS class names to avoid breaking current tests and CSS overrides in consumers' codebases.
Related
-
Reveal
A toggle that reveals additional content to the user when triggered.
-
Modal
A pop-up window used to request information, confirm a decision, or provide additional context.
-
Accordion
A list of toggles that reveal or hide associated content.
-
DialogPrimitive
The foundational blocks of dialog components.