import { V1Flyout } from '@uhg-abyss/web/ui/Flyout';() => { return ( <React.Fragment> <Text asElement="p" css={{ 'abyss-text-root': { margin: '0 0 10px' } }}> V1Flyout example starts on the right of the screen. See 'V1Flyout Label'. </Text> <Text asElement="p" css={{ 'abyss-text-root': { margin: '0 0 10px' } }}> This V1Flyout can be opened with the access key 'F'; the underlined 'F' in the label is to indicate this. </Text> <Text asElement="p" css={{ 'abyss-text-root': { margin: '0 0 10px' } }}> Press Ctrl + Option + F on Mac (Chrome/Safari) or Alt + F on Windows (Chrome). </Text> <Text asElement="p" css={{ 'abyss-text-root': { margin: '0 0 10px' } }}> See the Access Key section below for more details, including a full list of shortcuts. </Text> <V1Flyout position="right" label="V1Flyout Label" indent="60%" variant="filled" > <styled.div css={{ padding: '$web.semantic.spacing.scale.md', }} > <Text asElement="p" css={{ 'abyss-text-root': { margin: '0 0 10px' } }} > Here is the V1Flyout content from the sandbox example. </Text> </styled.div> </V1Flyout> </React.Fragment> );};Access key
The accessKey prop sets a keyboard shortcut to open the V1Flyout from anywhere on the page. This is recommended for accessibility purposes, for users who navigate with the keyboard.
By default, accessKey is set to the first character of the label prop, assuming a label is provided. As a visual indicator, the first character of the label is underlined and bolded to show the access key. To disable this, use the disableUnderlineAccessKey prop.
If a custom access key is set via the prop, no character is underlined/bolded in the label.
To disable the accessKey entirely, set the prop to an empty string.
The value must consist of a single printable character. This forms part of a keyboard shortcut, which varies depending on the browser and operating system.
For Chrome and Safari on Mac, the shortcut is Ctrl + Option + key. For Chrome on Windows, the shortcut is Alt + key.
See the MDN Web Docsopens in a new window for more information, including browser-specific shortcuts.
Button only
The primary function of the V1Flyout component, as the title suggests, is to expand a small V1Flyout drawer via a sticky button.
Additionally, the V1Flyout component can be used as a button, to do something like open a modal or a link. This is achieved by passing the buttonOnly prop.
Use the onClick prop to customize the action of the button, such as to open a modal.
To use the button as a link, see the href prop.
Variant
The variant prop offers two color/styling options for the button - 'filled' and 'outlined'.
'filled' is designed for the classic flyout scenario where a small drawer can expand out.
'outlined' is a secondary style, and is useful for actions such as going to an external feedback form via the onClick callback. It can technically be used in the same way as the filled variant, too. For example, if there are 2 different Flyouts on the same page, one can be filled and the other outlined.
Positioning
Use the position prop to change where the V1Flyout is anchored on the screen. Options include 'right' or 'bottom' The default position is 'right'.
The indent prop offsets the V1Flyout from its anchored edge. This prop accepts values like pixels ('px') or percentages ('%') to represent the offset distance. The default indent is '35%'.
- With
position="right", increasing theindentvalue moves the V1Flyout vertically, away from the bottom of the screen. - For
position="bottom", increasing theindentvalues moves the V1Flyout horizontally away from the right side of the screen.
<V1Flyout> can be anchored to either the right side or bottom of a screen, as specified by the required position prop.
Further customization of the <V1Flyout> position can be made with the indent prop.
If the position is 'bottom', the indent specifies how far up from the bottom of the screen the <V1Flyout> is positioned.
If the position is 'right', the indent specifies how far up from the right the <V1Flyout> is positioned.
indent examples include '30px' or '50%'.
href
The href prop allows the V1Flyout to act as a link. When the V1Flyout is clicked, the user is redirected to the specified URL.
See the ButtonOnly example for a use case.
Height and width
The height and width props set the size of the V1Flyout's opened content drawer.
The Abyss design team has specified a recommended height and width:
heightshould be between208pxand320px(default:208px)widthshould be between400pxand504px(default:400px)
When the variant is 'filled', and the position is 'right', the height of the button is fixed to match the height of the opened menu.
Otherwise, the button is sized dynamically.
Icon
An icon can be added to the left side of the V1Flyout button by passing an Icon or IconSymbol component to the icon prop.
The left icon is customizable. The right icon is reserved for a chevron icon that can be toggled on or off with the showArrowIcon prop - see below.
For examples, see Positioning or Variant.
Show arrow icon
The showArrowIcon prop displays a chevron icon on the right side of the V1Flyout button. This is useful for indicating that the button expands a drawer.
Overflow scrolling
When the V1Flyout is expanded, the V1Flyout content is scrollable if the content exceeds the height of the V1Flyout.
Content focus
The contentFocus prop allows the V1Flyout content container to receive focus when the V1Flyout is expanded. Then, keyboard users can use the tab key to navigate to the content.
This is intended to be used if the contents of the V1Flyout overflow. Otherwise, it adds an unnecessary tab stop.
If there are interactive elements placed within the V1Flyout content, these will already appear in the tab order, regardless of the contentFocus prop. For example, form controls (<input>, <textarea>, <select>), Links (<a>), and Buttons (<button>) appear in the tab order by default.
Responsiveness
When the screen hits a breakpoint of 744px or smaller, to ensure visibility of the component, we instead display the expanded form as a full-screen ModalDialog.
V1Flyout Props
| Name | Type | Default | A11y | Description |
|---|---|---|---|---|
accessKey | string | undefined | the first character of the button label | Sets the access key to open the Flyout with a keyboard shortcut. This string value must consist of a single printable character (which includes accented and other characters that can be generated by the keyboard). The way to utilize the access key depends on the browser and operating system. For example, on Mac with Chrome or Safari, the key combination is 'Control + Option + key'. | |
buttonOnly | boolean | undefined | false | This prop disables the primary functionality of the Flyout, which is to expand a Flyout menu. If true, the sticky button will just be, well, a button. The button can then be assigned a custom onClick function, for example, to open a link, or a modal. | |
children | string | number | bigint | boolean | ReactElement<any, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<...> | null | undefined | Element displayed when the Flyout is expanded. (i.e. the content of the opened Flyout) | ||
className | string | undefined | CSS class name to apply to each element within the component | ||
color | string | undefined | '$web.semantic.color.surface.interactive.standards.rest.default.primary' | The color of the FlyoutButton. Can be a CSS color string or a token. By default it uses the primary1 token from the theme. | |
contentFocus | boolean | undefined | false | If true, the content of the Flyout will be focusable. In other words, it can be accessed by keyboard navigation using the tab button. | |
css | CSSProperties | Partial<Record<"abyss-flyout-root-container" | "abyss-flyout-body-button" | "abyss-flyout-button" | "abyss-flyout-content", CSSProperties>> | undefined | Object containing CSS styling to apply; uses the classes listed in the "Integration" tab of the component's documentation See CSS Prop Styling for more information | ||
data-testid | string | undefined | Suffix used to create a unique ID used for automated testing See Component Testing for more information | ||
disableUnderlineAccessKey | boolean | undefined | false | Underlines and bolds the first character of the Flyout to indicate the access key. | |
height | string | number | undefined | '208px' | Sets the height of the expanded Flyout menu. Can be a CSS string or a number. The min height is 208px, and the max is 320px. | |
hiddenFrom | Breakpoint | undefined | When defined, the component is hidden once the screen width reaches the specified breakpoint. | ||
href | string | undefined | The href attribute for the FlyoutButton. If provided, the button will be rendered as an <a> element. To be used in conjunction with buttonOnly={true}. | ||
icon | Element | null | undefined | null | The icon element to be displayed to the left of the label on the FlyoutButton. Can be an instance of Icon or IconSymbol, or null. | |
indent | string | undefined | '25%' | Sets the placement of Flyout component along the edge of the page. Can be a CSS string such as percent or px. | |
label | string | undefined | '' | The label text of the FlyoutButton; this is its accessible name for screen readers. | |
onClick | ((isExpanded?: boolean | undefined) => void) | undefined | () => {} | A custom onClick function to be called when the FlyoutButton is clicked. It receives the current expanded state as a parameter. This makes the most sense to use with the buttonOnly prop set to true, allowing the button's onClick to be fully customized. Otherwise, the onClick will both toggle the Flyout and call this function. if buttonOnly is false, isExpanded will be provided as a parameter to the onClick function. if buttonOnly is true, isExpanded will always be false. | |
position | "right" | "bottom" | undefined | 'right' | The position of the Flyout. Can be either 'right' or 'bottom'. | |
showArrowIcon | boolean | undefined | true | Determines if the arrow icon is shown on the FlyoutButton, to the right of the label. The arrow icon is intended to indicate that the button will open a menu when clicked. Default is true, but if using buttonOnly to disable opening the Flyout menu, it may make sense to set this to false. | |
slotProps | FlyoutSlotPropsMap | undefined | Props to pass to individual internal slots of the component. To target slots inside sub-components (e.g. the trigger button or the content drawer), nest the sub-component's slotProps under the parent slot key: slotProps={{ 'flyout-button': { slotProps: { '<inner-key>': {...} } } }} See slotProps for more information | ||
variant | "filled" | "outlined" | undefined | 'filled' | The variant of the Flyout. Can be either 'filled' or 'outlined'. | |
visibleFrom | Breakpoint | undefined | When defined, the component is hidden until the screen width reaches the specified breakpoint. | ||
width | string | number | undefined | '400px' | Sets the width of the expanded Flyout menu. Can be a CSS string or a number. The min width is 400px, and the max is 504px. |
V1Flyout Classes
| Class Name | Description |
|---|---|
| .abyss-flyout-body-button | Skip-link-style button inserted at the start of the DOM to open the Flyout |
| .abyss-flyout-button | The button which opens/closes the Flyout menu |
| .abyss-flyout-content | The content drawer shown when the Flyout is expanded |
| .abyss-flyout-root-container | Fixed-position container for the Flyout button and content |
The V1Flyout component is composed of two parts: a "sticky" button positioned on the side of the browser window and modal drawer (dialog) that displayed when activated. When collapsed or displayed, the V1Flyout button and modal overlay the main content.
Communicating sticky button presence and keyboard access
Since the button is sticky, repositioned to the sides of browser window, and added to the end of the HTML. As result many users, especially those using screen readers, may not realize the button even exists. Keyboard users, if they know the button exists, would have difficulty accessing it in the focus order since is at the end of HTML <body>.
Skip links added to top of page
To address both issues, skip links are added to the very top of the page and (ideally) before any "skip to main content" option. Screen reader users are informed of these options at the start of the page. Minor changes for some browsers were made to help avoid known conflicts (See BrAT Accesskey Variations below).
Accesskey keyboard shortcut
The skip link also includes the keyboard shortcut to access the V1Flyout. This uses the standard HTML accesskey which should be familiar to them and their variations (See BrAT Accesskey Variations below). By default, the first letter of V1Flyout.Label becomes the shortcut key. By default, it is also underlined in the sticky button as a reminder for sighted users. These settings can be overridden (See the Access Key section in the Overview tab).
Closing V1Flyout returns to previous location
Like modal dialogs, closing a V1Flyout (should) return the focus to whatever element had it when it was opened. V1Flyout implements this so focus returns to the element that had it when closed. Flyouts can be closed using Escape, pressing Enter on the flyout button, or pressing the flyout accesskey combination again.
WAI-ARIA dialog pattern
The closest WAI-ARIA design pattern is the Dialog (Modal) Patternopens in a new window and Modal Dialog Exampleopens in a new window. WAI-ARIA currently (WAI-AIRA 1.1 as of 8/1/2024) has no equivalent to the sticky button and its keyboard access. The design and implementation used were created to address the issue covered above.
BrAT Accesskey Variations
-
Windows browsers (Chrome, Edge, Firefox) and screen readers (NVDA, JAWS)
-
Minor accesskey variation: Addition of Shift key
Windows accesskey for Chrome and Edge relies on Alt alone. This can cause conflicts accessing some characters Chromium browsers use for their keyboard shortcuts.
Firefox browser's accesskey implementation requires using Alt + Shift. Using Alt + Shift with the character addresses the issue with letter keys and works the same in all three browsers. This is why the skip links at the top of the page include Shift on Chromium browsers even though they may not be necessary.
Example: On this page, the sandbox example uses accesskey="F" to access the "V1Flyout Label" example on the right side of this window. Using Edge and Chrome Alt + F opens the File menu. Using Alt + Shift + F accesses V1Flyout Label as intended.
-
-
MacOS browsers (Safari, Chrome) and screen readers (VoiceOver)
- VoiceOver conflict with browser accesskey default
- MacOS uses Control + Option and this is shown in the skip link in Safari and Chrome browsers.
- VoiceOver uses Control + Option as its modifier keys creating a conflict when used in the browsers (discussed below)
- Safari
- Keyboard without VoiceOver: Control + Option + Letter (default)
- Keyboard with VoiceOver: Control + Letter ONLY
- Apple modifies Safari's HTML accesskey implementation to use only Control when VoiceOver is running
- Using modified accesskey using Control + [letter] works as described above including resetting focus to originally focused element using Escape, accesskey, and flyout button
- Note: Once activated, the Control-only accesskey modification is persistent even if VoiceOver is turned off. Restart Safari without VoiceOver to reset accesskey to Control + Option.
- Chrome
- Keyboard without VoiceOver: Control + Option + Letter (default)
- Keyboard with VoiceOver: accesskey "effectively disabled"
- Unlike Safari, the HTML accesskey modifier combination remains Control + Option
- To use this accesskey combination requires using VoiceOver pass-through mode using Control + Option + Tab
- Then use normal Control + Option accesskey combination to open flyout. Operation then works as described resetting focus to originally focused element using Escape, accesskey, and flyout button
- Example: To access the V1Flyout Label example requires pressing Control + Option + Tab, then Control + Option + F
- VoiceOver conflict with browser accesskey default
-
For more information about accesskey BrAT implementations see: Accesskey Accessibility Demo (pauljadam.com)opens in a new window
Keyboard Interactions
| Key | Description |
|---|---|
| Enter | Executes the V1Flyout button trigger to expand or close (when focus is on button) |
| Space | Executes the V1Flyout button trigger to expand or close (when focus is on button) |
| Esc | Closes the V1Flyout |
| Tab | Moves focus to V1Flyout content window when using contentFocus or to focusable element when present in content |