ContextualMenus are lists of commands that are based on the context of selection, mouse hover or keyboard focus. They are one of the most effective and highly used command surfaces, and can be used in a variety of places.
There are variants that originate from a command bar, or from cursor or focus. Those that come from CommandBars use a beak that is horizontally centered on the button. Ones that come from right click and menu button do not have a beak, but appear to the right and below the cursor. ContextualMenus can have submenus from commands, show selection checks, and icons.
Organize commands in groups divided by rules. This helps users remember command locations, or find less used commands based on proximity to others. One should also group sets of mutually exclusive or multiple selectable options. Use icons sparingly, for high value commands, and don’t mix icons with selection checks, as it makes parsing commands difficult. Avoid submenus of submenus as they can be difficult to invoke or remember.
For more details and examples visit the official docs. The R package cannot handle each and every case, so for advanced use cases you need to work using the original docs to achieve the desired result.
Arguments
- ...
Props to pass to the component. The allowed props are listed below in the Details section.
Details
className
string
Additional css class to apply to the ContextualMenuItemclassNames
IMenuItemClassNames
Classnames for different aspects of a menu itemcomponentRef
IRefObject<IContextualMenuRenderItem>
Optional callback to access the IContextualMenuRenderItem interface. Use this instead of ref for accessing the public methods and properties of the component.dismissMenu
(ev?: any, dismissAll?: boolean) => void
This prop will get set by ContextualMenu and can be called to close the menu this item belongs to. If dismissAll is true, all menus will be closed.dismissSubMenu
() => void
This prop will get set by ContextualMenu and can be called to close this item's subMenu, if present.getSubmenuTarget
() => HTMLElement | undefined
This prop will get set by the wrapping component and will return the element that wraps this ContextualMenuItem. Used for openSubMenu.hasIcons
boolean | undefined
If this item has iconsindex
number
Index of the itemitem
IContextualMenuItem
The item to displayonCheckmarkClick
(item: IContextualMenuItem, ev: React.MouseEvent<HTMLElement>) => void
Click handler for the checkmarkopenSubMenu
(item: any, target: HTMLElement) => void
This prop will get set by ContextualMenu and can be called to open this item's subMenu, if present.styles
IStyleFunctionOrObject<IContextualMenuItemStyleProps, IContextualMenuItemStyles>
Call to provide customized styling that will layer on top of the variant rules.theme
ITheme
Theme provided by High-Order Component.focusableElementIndex
number
hasCheckmarks
boolean
hasIcons
boolean
index
number
totalItemCount
number
defaultMenuItemRenderer
(item: IContextualMenuItemRenderProps) => React.ReactNode
hasCheckmarks
boolean
hasIcons
boolean
items
IContextualMenuItem[]
role
string
totalItemCount
number
alignTargetEdge
boolean
If true the positioning logic will prefer to flip edges rather than to nudge the rectangle to fit within bounds, thus making sure the element aligns perfectly with target's alignment edgeariaLabel
string
Accessible label for the ContextualMenu's root element (inside the callout).beakWidth
number
The width of the beak.bounds
IRectangle | ((target?: Target, targetWindow?: Window) => IRectangle | undefined)
The bounding rectangle (or callback that returns a rectangle) which the contextual menu can appear in.calloutProps
ICalloutProps
Additional custom props for the Callout.className
string
Additional CSS class to apply to the ContextualMenu.componentRef
IRefObject<IContextualMenu>
Optional callback to access the IContextualMenu interface. Use this instead of ref for accessing the public methods and properties of the component.contextualMenuItemAs
React.ComponentClass<IContextualMenuItemProps> | React.FunctionComponent<IContextualMenuItemProps>
Custom component to use for rendering individual menu items.coverTarget
boolean
If true, the menu will be positioned to cover the target. If false, it will be positioned next to the target.delayUpdateFocusOnHover
boolean
If true, the contextual menu will not be updated until focus enters the menu via other means. This will only result in different behavior whenshouldFocusOnMount = false
.directionalHint
DirectionalHint
How the menu should be positioneddirectionalHintFixed
boolean
If true the position will not change sides in an attempt to fit the ContextualMenu within bounds. It will still attempt to align it to whatever bounds are given.directionalHintForRTL
DirectionalHint
How the menu should be positioned in RTL layouts. If not specified, a mirror ofdirectionalHint
will be used.doNotLayer
boolean
If true do not render on a new layer. If false render on a new layer.focusZoneProps
IFocusZoneProps
Props to pass down to the FocusZone. NOTE: the default FocusZoneDirection will be used unless a direction is specified in the focusZoneProps (even if other focusZoneProps are defined)gapSpace
number
The gap between the ContextualMenu and the targetgetMenuClassNames
(theme: ITheme, className?: string) => IContextualMenuClassNames
Method to provide the classnames to style the contextual menu.hidden
boolean
If true, renders the ContextualMenu in a hidden state. Use this flag, rather than rendering a ContextualMenu conditionally based on visibility, to improve rendering performance when it becomes visible. Note: When ContextualMenu is hidden its content will not be rendered. It will only render once the ContextualMenu is visible.id
string
ID for the ContextualMenu's root element (inside the callout). Should be used foraria-owns
and other such uses, rather than direct reference for programmatic purposes.isBeakVisible
boolean
If true then the beak is visible. If false it will not be shown.isSubMenu
boolean
Whether this menu is a submenu of another menu.items
IContextualMenuItem[]
Menu items to display.labelElementId
string
Used asaria-labelledby
for the menu element inside the callout.onDismiss
(ev?: React.MouseEvent | React.KeyboardEvent, dismissAll?: boolean) => void
Callback when the ContextualMenu tries to close. IfdismissAll
is true then all submenus will be dismissed.onItemClick
(ev?: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>, item?: IContextualMenuItem) => boolean | void
Click handler which is invoked ifonClick
is not passed for individual contextual menu item. Returning true will dismiss the menu even ifev.preventDefault()
was called.onMenuDismissed
(contextualMenu?: IContextualMenuProps) => void
Callback for when the menu is being closed (removing from the DOM).onMenuOpened
(contextualMenu?: IContextualMenuProps) => void
Callback for when the menu has been opened.onRenderMenuList
IRenderFunction<IContextualMenuListProps>
Method to override the render of the list of menu items.onRenderSubMenu
IRenderFunction<IContextualMenuProps>
Custom render function for a submenu.onRestoreFocus
(options: { originalElement?: HTMLElement | Window; containsFocus: boolean; }) => void
Called when the component is unmounting, and focus needs to be restored. Argument passed down contains two variables, the element that the underlying popup believes focus should go to and whether or not the popup currently contains focus. If this prop is provided, focus will not be restored automatically, you'll need to call originalElement.focus()shouldFocusOnContainer
boolean
Whether to focus on the contextual menu container (as opposed to the first menu item).shouldFocusOnMount
boolean
Whether to focus on the menu when mounted.shouldUpdateWhenHidden
boolean
If true, the menu will be updated even whenhidden=true
. Note that this will consume resources to update even when nothing is being shown to the user. This might be helpful if your updates are small and you want the menu to display quickly whenhidden
is set to false.styles
IStyleFunctionOrObject<IContextualMenuStyleProps, IContextualMenuStyles>
Call to provide customized styling that will layer on top of the variant rules.subMenuHoverDelay
number
Delay (in milliseconds) to wait before expanding / dismissing a submenu on mouseEnter or mouseLeavetarget
Target
The target that the ContextualMenu should try to position itself based on. It can be either an element, a query selector string resolving to a valid element, or a MouseEvent. If a MouseEvent is given, the origin point of the event will be used.theme
ITheme
Theme provided by higher-order component.title
string
Title to be displayed at the top of the menu, above the items.useTargetAsMinWidth
boolean
If true the context menu will have a minimum width equal to the width of the target elementuseTargetWidth
boolean
If true the context menu will render as the same width as the target element
Examples
library(shiny)
library(shiny.fluent)
ui <- function(id) {
ns <- NS(id)
div(
DefaultButton.shinyInput(
ns("toggleContextualMenu"),
id = "target",
text = "Toggle menu"
),
reactOutput(ns("contextualMenu"))
)
}
server <- function(id) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
showContextualMenu <- reactiveVal(FALSE)
observeEvent(input$toggleContextualMenu, {
showContextualMenu(!showContextualMenu())
})
output$contextualMenu <- renderReact({
menuItems <- JS("[
{
key: 'newItem',
text: 'New',
onClick: () => console.log('New clicked'),
},
{
key: 'divider_1',
itemType: 1,
},
{
key: 'rename',
text: 'Rename',
onClick: () => console.log('Rename clicked'),
},
{
key: 'edit',
text: 'Edit',
onClick: () => console.log('Edit clicked'),
},
{
key: 'properties',
text: 'Properties',
onClick: () => console.log('Properties clicked'),
},
{
key: 'linkNoTarget',
text: 'Link same window',
href: 'http://bing.com',
},
{
key: 'linkWithTarget',
text: 'Link new window',
href: 'http://bing.com',
target: '_blank',
},
{
key: 'linkWithOnClick',
name: 'Link click',
href: 'http://bing.com',
onClick: function(){
alert('Link clicked');
ev.preventDefault();
},
target: '_blank',
},
{
key: 'disabled',
text: 'Disabled item',
disabled: true,
onClick: () => console.error('Disabled item should not be clickable.'),
},
]")
ContextualMenu(
items = menuItems,
hidden = !showContextualMenu(),
target = "#target",
onItemClick = JS(paste0(
"function() {",
" Shiny.setInputValue('", ns("toggleContextualMenu"), "', Math.random());",
"}"
)),
onDismiss = JS(paste0(
"function() {",
" Shiny.setInputValue('", ns("toggleContextualMenu"), "', Math.random());",
"}"
))
)
})
})
}
if (interactive()) {
shinyApp(ui("app"), function(input, output) server("app"))
}