Components

Menu - New!

Menu is an ecosystem of components that provide a structured and accessible way to create menus.

Prebuilt Toggle Elements

The menuToggleElement prop determines what element or component triggers your menu to open and close. Seeds provides several toggle components to cover a variety of use cases, from simple buttons to accessible listbox triggers and custom input fields.

Below are the available toggle components, their use cases, and example usage.

Accessibility:
All prebuilt toggle components are designed for accessibility out of the box. When building a custom toggle, be sure to follow accessibility guidelines and use the provided context hooks.

The MenuToggleButton is a button designed to trigger the opening and closing of menus. Its props are interchangeable with .

Use case:
The default and most common toggle for menus. Use this for standard dropdowns, action menus, and most menu scenarios where a button is appropriate.

MenuToggleButton accepts all the same props as .

NameTypeDefaultDescriptionRequired?
external
boolean
If the button is being used as an anchor, this prop will cause the link to open in a new tab.
size
"large"
"small"
"default"
"default"
appearance
"primary"
"secondary"
"pill"
"destructive"
"unstyled"
"placeholder"
"unstyled"
What the button looks like.
active
boolean
false
Set the button to display in its active state
disabled
boolean
Disables user action and applies a disabled style on the button
children
React.ReactNode
href
string
Setting this prop will cause the component to be rendered as an anchor element instead of a button element
download
string
If the component is rendered as an anchor to a file, this prop sets the name of the file to be downloaded
innerRef
React.Ref<HTMLButtonElement>
Used to get a reference to the underlying button
onClick
React.MouseEventHandler<HTMLButtonElement>
Action to perform when the button is clicked
title
string
qa
object
{}
as
TypeStyledComponentsCommonProps["as"]
ariaLabel
string
Label used to describe the button if the button does not have text within it

This example shows how to use MenuToggleButton as a menu trigger. Example:

import { MenuToggleButton } from '@sproutsocial/seeds-react-menu'
<Box display="flex" justifyContent="center" alignItems="center" height="100%">
<ActionMenu
menuToggleElement={
<MenuToggleButton appearance="primary">
I'm a MenuToggleButton
</MenuToggleButton>
}
>
<MenuContent>
<MenuItem id="item-one">Item 1</MenuItem>
<MenuItem id="item-two">Item 2</MenuItem>
<MenuItem id="item-three">Item 3</MenuItem>
</MenuContent>
</ActionMenu>
</Box>

View MenuToggleButton in Storybook

ListboxToggleButton

ListboxToggleButton extends MenuToggleButton and is styled to look like a select dropdown.
It accepts all the same props as MenuToggleButton, with an additional invalid prop for error state styling.

Use case:
Use when you want your menu trigger to look and behave like a native select dropdown.

NameTypeDefaultDescriptionRequired?
invalid
boolean

This example demonstrates ListboxToggleButton styled as a select dropdown trigger. Example:

import { ListboxToggleButton } from '@sproutsocial/seeds-react-menu'
<Box display="flex" justifyContent="center" alignItems="center" height="100%">
<SingleSelectMenu
menuToggleElement={
<ListboxToggleButton>
Open Listbox
</ListboxToggleButton>
}
>
<MenuContent>
<MenuItem id="item-one">Item 1</MenuItem>
<MenuItem id="item-two">Item 2</MenuItem>
<MenuItem id="item-three">Item 3</MenuItem>
</MenuContent>
</SingleSelectMenu>
</Box>

MenuLabel extends the component, but manages association with the menu toggle automatically—so you should not provide an htmlFor prop. It is used to improve the accessibility of a menu by providing a text label for the menu's toggle element.

Use case:
Use MenuLabel to provide an accessible, visible label for your menu toggle, especially in form-like menus.

NameTypeDefaultDescriptionRequired?
children
React.ReactNode
required
boolean
false
Whether making a selection in the associated menu is required.
htmlFor
never
ID of the associated form element. This prop is never valid to pass into MenuLabel because MenuLabel passes its own htmlFor prop to the underlying Label component.

This example shows how to pair MenuLabel with ListboxToggleButton for an accessible labeled menu trigger. Example:

import { MenuLabel, ListboxToggleButton, SingleSelectMenu, MenuContent, MenuItem } from '@sproutsocial/seeds-react-menu'
<Box display="flex" justifyContent="center" alignItems="center" height="100%">
<SingleSelectMenu
menuToggleElement={
<>
<MenuLabel mr={300}>Choose an option:</MenuLabel>
<ListboxToggleButton>
Open Listbox
</ListboxToggleButton>
</>
}
>
<MenuContent>
<MenuItem id="item-one">Item 1</MenuItem>
<MenuItem id="item-two">Item 2</MenuItem>
<MenuItem id="item-three">Item 3</MenuItem>
</MenuContent>
</SingleSelectMenu>
</Box>

AutocompleteInput as Toggle

AutocompleteInput extends the component, but its event listeners (such as onKeyDown, onChange, etc.) are adapted for compatibility with Downshift’s combobox pattern. This ensures seamless integration with menu state and accessibility features when used as a menu toggle.

Use case:
For searchable menus, use an AutocompleteInput inside a as your toggle. This pattern is common for single-select autocomplete menus.

This example demonstrates using AutocompleteInput inside a form field as a searchable menu toggle. Example:

import { Autocomplete, AutocompleteInput, FormField, MenuLabel, MenuContent, MenuItem } from '@sproutsocial/seeds-react-menu'
<Box display="flex" justifyContent="center" alignItems="center" height="100%">
<Autocomplete
menuToggleElement={
<FormField label={<MenuLabel>Search books</MenuLabel>}>
{props => <AutocompleteInput {...props} />}
</FormField>
}
>
<MenuContent>
<MenuItem id="book-1">Book One</MenuItem>
<MenuItem id="book-2">Book Two</MenuItem>
<MenuItem id="book-3">Book Three</MenuItem>
</MenuContent>
</Autocomplete>
</Box>

AutocompleteTokenInput as Toggle

AutocompleteTokenInput extends the component, adapting its event listeners for compatibility with Downshift’s combobox pattern and supporting rendering multiple selected items as tokens.

Use case:
For multi-select autocomplete menus, use an AutocompleteTokenInput inside a as your toggle. This allows users to select multiple items and see them as tokens.

NameTypeDefaultDescriptionRequired?
getTokenProps
(itemId: string) => Partial<TypeTokenSpec>
A function that can be passed to override the default token props
MenuContext
MenuToggleContext
MenuContentContext
createContext<TypeMenuToggleContext>(defaultMenuContext)
Specify the menu context to use. MenuToggleContext is the default. This prop is only needed for specialized use cases.

This example shows AutocompleteTokenInput used as a multi-select autocomplete menu toggle, displaying selected items as tokens. Example:

import { Autocomplete, AutocompleteTokenInput, FormField, MenuLabel, MenuContent, MenuItem } from '@sproutsocial/seeds-react-menu'
<Box display="flex" justifyContent="center" alignItems="center" height="100%">
<Autocomplete
multiSelect
menuToggleElement={
<FormField label={<MenuLabel>Search and select books</MenuLabel>} width="250px">
{props => <AutocompleteTokenInput {...props} />}
</FormField>
}
>
<MenuContent>
<MenuItem id="book-1">Book One</MenuItem>
<MenuItem id="book-2">Book Two</MenuItem>
<MenuItem id="book-3">Book Three</MenuItem>
</MenuContent>
</Autocomplete>
</Box>

Using Custom Toggle Elements

You can create your own custom toggle element by using the useMenuToggleContext and calling getToggleButtonProps. This is useful if you want to use a non-standard element as your menu trigger.

Note:
For the best experience, we recommend using our prebuilt toggle components above.
The following is an advanced pattern intended for custom use cases where you need to build your own toggle element and handle menu state directly. When building a custom toggle, be sure to follow accessibility guidelines and use the provided context hooks to ensure your menu remains accessible.

This example demonstrates creating a custom menu toggle using useMenuToggleContext and getToggleButtonProps. Example:

import { useMenuToggleContext } from '@sproutsocial/seeds-react-menu'
() => {
// A custom toggle button using getToggleProps from MenuToggleContext
const CustomToggle = () => {
const { getToggleButtonProps, isOpen, isListbox, ref, ariaProps } = useMenuToggleContext();
return (
<Button
{...getToggleButtonProps?.({
// adds the ref from the Popout component
ref,
// specifies the prop used on the Button component for the ref
refKey: "innerRef",
// adds the aria tags coming from the Popout component
...ariaProps,
// adds the correct role if this is an ActionMenu
...(isListbox ? {} : { role: "button", "aria-haspopup": "menu" }),
})}
style={{
padding: "8px 16px",
background: isOpen ? "#e0f7fa" : "#fff",
border: "2px solid #00bcd4",
borderRadius: 4,
cursor: "pointer",
fontWeight: "bold"
}}
>
{isOpen ? "Close" : "Open"} Custom Menu
</Button>
);
};
return (
<Box display="flex" justifyContent="center" alignItems="center" height="100%">
<ActionMenu menuToggleElement={<CustomToggle />}>
<MenuContent>
<MenuItem id="item-one">Item 1</MenuItem>
<MenuItem id="item-two">Item 2</MenuItem>
<MenuItem id="item-three">Item 3</MenuItem>
</MenuContent>
</ActionMenu>
</Box>
);
}