跳到主要内容

ContextMenuButton

Icon that opens a menu of actions, built afresh from a callback each time it is clicked. The callback is what the menu shows — the data prop is read once and then forgotten.

ContextMenuButtonContextMenuButton

Use this when / not when​

  • Use for the "more" button of a row, a card or a toolbar, where the actions depend on what is selected at the moment of the click.
  • Not for a right-click menu on a region — that is ContextMenu, which this one opens for Row in its toggle mode.
  • Not for choosing a value: ComboBox.
  • Not for a menu you control yourself — DropDown anchored to an IconButton of your own is less indirect.

Import​

import {
ContextMenuButton,
ContextMenuButtonDisplayType,
} from "@onlyoffice/apps-ui-kit/components/context-menu-button";

Also exported from the root barrel @onlyoffice/apps-ui-kit.

Needs ThemeProvider from @onlyoffice/apps-ui-kit/providers/theme for the icon and menu colours, and TranslationProvider from @onlyoffice/apps-ui-kit/providers/translation because the items are DropDownItems.

Stories​

Default​

The row-level "more" button: click the dots to open the menu and click again or outside it to close it. Change any other prop live in the Controls panel below.

DefaultDefault

Disabled​

Use it when the actions do not apply to the current item: the icon greys out and a click opens nothing (isDisabled).

DisabledDisabled

With Icon Border​

Gives the icon a larger, boxed click target (displayIconBorder): the dots sit in a rounded 32px square. The default theme draws no line around it; set --cmb-border to add one, as the CSS customization story does.

With Icon BorderWith Icon Border

Custom Colors​

Matches the icon to the surface it sits on: each button has its own colour, and hovering it shows its hover colour (color, hoverColor). Click any to open its menu.

Custom ColorsCustom Colors

Css Customization​

Every overridable variable set on one wrapper -- the variables are listed under CSS variables on this page. The example opens the menu in a bordered box (displayIconBorder), so every variable is on screen at once; hover the dots to see --cmb-hover-border. The menu is kept inline (usePortal={false}): in a portal it leaves the wrapper, so set the --dropdown-* variables on document.body instead.

Css CustomizationCss Customization

Minimal example​

getData is what the menu is built from, and the component calls it without checking — a button without one throws on the first click.

import { ContextMenuButton } from "@onlyoffice/apps-ui-kit/components/context-menu-button";

export function RowActions({
onRename,
onDelete,
}: {
onRename: () => void;
onDelete: () => void;
}) {
return (
<ContextMenuButton
title="Actions"
getData={() => [
{ key: "rename", label: "Rename", onClick: onRename },
{ key: "delete", label: "Delete", onClick: onDelete },
]}
/>
);
}

Props​

PropertyTypeDescription
asideHeader?ReactNodeIgnored. Nothing reads this prop.
className?stringApplied to the wrapper around the icon and the menu.
clickColor?stringColour of the icon while it is held down.
color?stringAny CSS colour for the icon, or the literal "accent".
columnCount?numberIgnored. It reaches the menu, which does not read it either.
data?ContextMenuModel[]Items of the menu, read once to seed the internal state. Every later change is ignored — getData is what the open menu is built from. Default: [].
directionX?TDirectionXPreferred horizontal side of the menu. Default: "left".
directionY?TDirectionYPreferred vertical side of the menu.
displayIconBorder?booleanDraws a rounded border around the icon, 32px square. Default: false.
displayType?ContextMenuButtonDisplayTypetoggle renders no menu of its own and leaves onClick to open one; auto behaves exactly like dropdown. Default: ContextMenuButtonDisplayType.dropdown.
fixedDirection?booleanKeeps those directions as given instead of flipping them to fit. Default: false.
getData?() => ContextMenuModel[]Builds the items when the button is clicked. It is not optional in practice: the click handler calls it without checking, so a button without it throws on the first click.
hoverColor?stringColour of the icon while the pointer is over it.
iconClassName?stringApplied to the icon.
iconClickName?stringURL of the icon shown while the button is held down.
iconHoverName?stringURL of the icon shown while the pointer is over the button.
iconName?stringURL of the icon, fetched at runtime. Without it the kit's vertical dots are drawn.
iconOpenName?stringURL of the icon shown while the menu is open.
id?stringApplied to that wrapper.
isDisabled?booleanGreys the icon out and stops the menu opening. Default: false.
isFill?booleanColours the icon by filling its shapes rather than stroking them. Default: true.
onClick?(e: React.MouseEvent) => voidCalled on a click — after the menu has opened in dropdown mode, and instead of opening anything in toggle mode, where it is how you render a menu of your own.
onClose?() => voidCalled when the menu closes by itself, after a click outside.
onMouseEnter?(e: React.MouseEvent) => voidCalled when the pointer enters the icon.
onMouseLeave?(e: React.MouseEvent) => voidCalled when the pointer leaves the icon.
onMouseOut?(e: React.MouseEvent) => voidCalled on mouse up on the icon, despite the name, and only for the middle and right buttons.
onMouseOver?(e: React.MouseEvent) => voidCalled on mouse down on the icon, despite the name.
opened?booleanOpens the menu from outside. Changing it opens or closes the menu. Default: false.
size?numberSize of the icon in pixels. Default: 16.
style?CSSPropertiesApplied to that wrapper.
testId?stringValue of data-testid on the wrapper. Default: "context-menu-button".
title?stringHover tooltip of the icon. It needs RootTooltip mounted. Default: "".
usePortal?booleanWhether the menu is rendered in a portal on document.body. Default: true.
zIndex?numberStacking order of the menu.

Enums​

EnumMembers
ContextMenuButtonDisplayTypedropdown, toggle, auto

Recipes​

Open and close, controlled​

opened opens the menu when it changes, and onClose reports a close the component performed itself after a click outside.

import { useState } from "react";
import { ContextMenuButton } from "@onlyoffice/apps-ui-kit/components/context-menu-button";

export function ControlledActions({ onRename }: { onRename: () => void }) {
const [open, setOpen] = useState(false);

return (
<ContextMenuButton
opened={open}
onClose={() => setOpen(false)}
onClick={() => setOpen(true)}
getData={() => [{ key: "rename", label: "Rename", onClick: onRename }]}
/>
);
}

Disabled​

import { ContextMenuButton } from "@onlyoffice/apps-ui-kit/components/context-menu-button";

export function MaybeActions({ canEdit }: { canEdit: boolean }) {
return (
<ContextMenuButton
isDisabled={!canEdit}
title="Actions"
displayIconBorder
getData={() => [{ key: "rename", label: "Rename", onClick: () => {} }]}
/>
);
}

Behaviour the types don't state​

  • data is read once. It seeds the internal state on the first render and is never looked at again, so a menu whose items change has to supply them through getData, which is called on every click.
  • It re-renders only for four props. The component is memoised with a comparison that looks at opened, displayType, isDisabled and getData alone — a new title, color, iconName or handler does nothing until one of those four changes. Pass a stable getData that closes over fresh values, or key the component.
  • onMouseOver and onMouseOut are wired to the wrong events. They are handed to the icon as its onMouseDown and onMouseUp, and that onMouseUp itself only fires for the middle and right buttons — see IconButton.
  • displayType="auto" is dropdown. The function that would choose by width returns dropdown unconditionally. toggle is the one that differs: no menu is rendered at all and onClick is left to open one, which is how Row uses it.
  • The menu gets a backdrop only on a tablet or a phone, and a transparent one at that; on a desktop a click outside is caught by click and mousedown listeners instead.
  • The icon is the kit's vertical dots unless iconName gives a URL, which is fetched at runtime.
  • columnCount and asideHeader are declared and never read.

CSS variables​

VariableDefaultEffect
--cmb-size32pxWidth and height of the bordered box
--cmb-radius3pxCorner radius of that box
--cmb-icon-padding6px 7pxPadding between the border and the icon
--cmb-bordera theme grey, no lineBorder of the box, as a border shorthand
--cmb-hover-bordertheme greyColour of the border on hover

All five apply only with displayIconBorder. The theme's value for --cmb-border is a colour with no width or style, so by default the box draws no line at all, and --cmb-hover-border shows nothing until --cmb-border supplies a style, as in 1px solid.

The menu is a DropDown and reads its own --dropdown-* variables. By default it is portalled to document.body, outside the wrapper, so set them there, or pass usePortal={false} to keep the menu inside the element that sets them. The icon colour is set inline by the icon itself; change it with color, hoverColor and clickColor, not with a variable.

Accessibility​

  • The icon is an IconButton: a <div> with no role, no tab stop and no Enter or Space activation, so the menu cannot be opened from the keyboard; a keyboard route to the same actions has to come from the host.
  • The wrapper and the icon both carry aria-disabled while isDisabled, but there is no aria-haspopup or aria-expanded, and the menu is not linked to the button.
  • The items are role="option" rows in a role="listbox", which is not what a menu of actions is.
  • title renders the kit's hover tooltip, not an accessible name.

Test ids​

Elementdata-testid
The wrappercontext-menu-button, overridable with testId
An itemthe item's dataTestId, otherwise <key>_item
  • ContextMenu — the right-click menu, which toggle mode leaves you to open.
  • DropDown — the menu this renders, and its own props.
  • IconButton — the icon, and the props passed through to it.