Dropdown Button composes two components you already have. The trigger is a Button, the menu is a Dropdown Menu, and this adds the caret between them and hands on every prop it does not name itself.
Anatomy
Section titled “Anatomy”-
Button the trigger, and a full Button —Export CSVExport PDFShare linkExport CSVExport PDFShare linkvariant,sizeand the rest come straight from it. -
Caret icon the only thing in the closed state that promises a menu. It arrives as Button'sExport CSVExport PDFShare linkExport CSVExport PDFShare linksuffixIcon, so passing your own replaces it. -
Menu container (when open) the surface the actions sit on, anchored under the button.Export CSVExport PDFShare linkExport CSVExport PDFShare link -
Menu item (when open) one action.Export CSVExport PDFShare linkExport CSVExport PDFShare linkmenuItemsis required, and with none the button does not render either.
When to use
Section titled “When to use”A dropdown button collects the actions on one object that cannot all have a place on the surface. The button names what they have in common; the menu holds the rest.
Use a plain Button for a single action, and a Dropdown Menu directly when the trigger is not a button — an avatar, a row’s overflow icon, a table cell. Use Select or Combobox when the items are values the reader is choosing between rather than actions they are running: a menu closes and something has happened, a select closes and something has been set.
Behavior
Section titled “Behavior”A suffix icon replaces the caret rather than joining it
Section titled “A suffix icon replaces the caret rather than joining it”The caret is a suffixIcon the component passes to Button, and your props are
spread after it. So suffixIcon replaces the caret rather than joining it, and
the button loses the only thing in its closed state that says a menu is coming.
Put an icon on the left with prefixIcon instead.
variant and width arrive the same way: the component asks Button for
basic and auto, and anything you pass wins. The variants and the rule about
how many of them can be loud at once are on Button.
Portal the menu when an ancestor clips it
Section titled “Portal the menu when an ancestor clips it”The menu renders in place, next to the button in the DOM, because Dropdown Menu
does not portal by default. Any ancestor with hidden overflow — a card, a table
cell, a scrolling panel — will cut the menu off at its edge. Pass
menuProps={{ portal: true }} to move it to the end of the document instead.
A menu that is drawn behind a neighbor rather than cut off by an ancestor is
the other problem, and menuProps={{ zIndex }} is the lever for it.
side picks the edge the menu hangs from. It is aligned to the button’s end
edge unless you pass align through menuProps.
Never pass an empty item list
Section titled “Never pass an empty item list”menuItems is required, and an empty array takes the button with it — not a
button that opens nothing, but nothing at all. The mechanism belongs to
Dropdown Menu, which renders the trigger as one of
its own children. Where the list is filtered or fetched, render a disabled
Button instead of a Dropdown Button with nothing in it.
Accessibility
Section titled “Accessibility”Everything but the button’s name is already wired
Section titled “Everything but the button’s name is already wired”aria-haspopup, aria-expanded on the button, role="menu" on the surface and
role="menuitem" on each item are all set for you, and they stay in step with
the open state on their own. What is left to you is the button’s accessible
name, which is its visible text.
Enter, Space and Down Arrow open the menu; Escape closes it and returns focus to the button. The menu is not modal, so the page behind it stays interactive and a click outside both closes the menu and reaches whatever was clicked.
Content
Section titled “Content”Write the button label as the category the actions share
Section titled “Write the button label as the category the actions share”“Actions” and “More” are honest when the items have nothing in common, but a button that can say “Export” or “Manage members” has told the reader whether to open it at all. Naming the mechanism instead — “Menu”, “Options” — describes what the caret already shows.
Wording for the items themselves is on Dropdown Menu, and the rules for every label in the product are on Writing.
| Name | Type |
|---|---|
menuItemsrequired |
Use |
menuProps |
Additional props will be spread to the inner |
side |
The side of the dropdown menu. |
variant |
Visual style of the button.
|
isPending |
Shows a loading spinner and disables the button. Also triggers automatically when |
prefixIcon |
Icon rendered to the left of the button label. Import from |
prefixIconType |
Controls how the prefix icon inherits sizing.
|
suffixIcon |
Icon rendered to the right of the button label. Import from |
size |
Height and typography scale of the button. |
to |
Changes the button into a link. Pass a relative path to use |
target |
Overrides the target of the link if |
type |
Note: we may want to default this to ‘button’ in the future, but many instances of this Button component in dashboard currently rely on the default ‘submit’ behavior that occurs when using this in redux-form so we’ll have to comb through and manually add the type=‘submit’ prop. |
width |
Controls the width of the button.
|
onClick |
|
onSecondaryBackground |
In some cases we render a button on a secondary background, which needs an adjustment for certain variants. |
hovered |
Visual state override. Forces the |
focused |
Visual state override. Forces the |
active |
Visual state override. Forces the |
mixed |
Visual state override. Forces the |
ComponentPropsWithoutRef<‘button’>.Was this page helpful?