Multi-action button
A multi-action button is a combination of a dropdown and button. It lets users choose from multiple parallel actions to reduce visual complexity.
Loading...
Overview
Resources
Install
yarn add @camp/multi-action-buttonUpgrading to Next Gen
The Multi-Action Button has been consolidated from @activecampaign/camp-components-multi-action-button into @camp/multi-action-button. This is a direct 1-to-1 move with no API changes.
- 🧩 Same API: All props remain identical — no breaking changes
Previous implementation
import MultiActionButton from '@activecampaign/camp-components-multi-action-button';
<MultiActionButton
appearance="primary"
options={[
{ label: 'Option 1', value: 'option-1' },
{ label: 'Option 2', value: 'option-2' },
{ label: 'Option 3', value: 'option-3' },
]}
triggerLabel="More actions"
optionToString={(option) => option.label}
onButtonClick={() => {}}
onOptionClick={(option) => {}}
>
Primary Action
</MultiActionButton>;New implementation
import MultiActionButton from '@camp/multi-action-button';
<MultiActionButton
appearance="primary"
options={[
{ label: 'Option 1', value: 'option-1' },
{ label: 'Option 2', value: 'option-2' },
{ label: 'Option 3', value: 'option-3' },
]}
triggerLabel="More actions"
optionToString={(option) => option.label}
onButtonClick={() => {}}
onOptionClick={(option) => {}}
>
Primary Action
</MultiActionButton>;Migration steps
- Update the import path from
@activecampaign/camp-components-multi-action-buttonto@camp/multi-action-button - No prop changes are required — the API is identical
- Your existing option shapes (e.g.
{ text: 'Copy' }) still work — just keep youroptionToStringaligned with the shape you pass
Variations
Multi-action buttons provide a primary action and a menu of related actions. They are commonly used in tables. Multi-action buttons largely follow the styling of the Camp button component, and have both primary and secondary appearances.
All Variants
An overview of all button appearances and sizes, including secondary, primary, small, and disabled states.
import MultiActionButton from '@camp/multi-action-button';
const options = [
{ label: 'Option 1', value: 'option-1' },
{ label: 'Option 2', value: 'option-2' },
{ label: 'Option 3', value: 'option-3' },
];
// Secondary Medium (default)
<MultiActionButton
options={options}
triggerLabel="More actions"
optionToString={(option) => option.label}
onButtonClick={() => {}}
onOptionClick={(option) => {}}
>
Secondary Medium
</MultiActionButton>
// Primary Medium
<MultiActionButton
appearance="primary"
options={options}
triggerLabel="More actions"
optionToString={(option) => option.label}
onButtonClick={() => {}}
onOptionClick={(option) => {}}
>
Primary Medium
</MultiActionButton>
// Small size
<MultiActionButton
appearance="secondary"
size="small"
options={options}
triggerLabel="More actions"
optionToString={(option) => option.label}
onButtonClick={() => {}}
onOptionClick={(option) => {}}
>
Secondary Small
</MultiActionButton>Primary Button
The primary appearance of the multi-action button is used sparingly. It’s typically used in a page header bar to indicate multiple page-level actions a user can take.
import MultiActionButton from '@camp/multi-action-button';
<MultiActionButton
appearance="primary"
options={[
{ label: 'Option 1', value: 'option-1' },
{ label: 'Option 2', value: 'option-2' },
{ label: 'Option 3', value: 'option-3' },
]}
triggerLabel="More actions"
optionToString={(option) => option.label}
onButtonClick={() => {}}
onOptionClick={(option) => {}}
>
Primary Action
</MultiActionButton>;Secondary Button
The secondary multi-action button appearance is the default appearance. It is named to align with Camp’s secondary button. Use it within a table to provide a menu of table row actions to the user.
import MultiActionButton from '@camp/multi-action-button';
<MultiActionButton
options={[
{ label: 'Option 1', value: 'option-1' },
{ label: 'Option 2', value: 'option-2' },
{ label: 'Option 3', value: 'option-3' },
]}
triggerLabel="More actions"
optionToString={(option) => option.label}
onButtonClick={() => {}}
onOptionClick={(option) => {}}
>
Secondary Action
</MultiActionButton>;Disabled
Both primary and secondary variants support a disabled state that prevents interaction.
import MultiActionButton from '@camp/multi-action-button';
<MultiActionButton
appearance="secondary"
disabled
options={[
{ label: 'Option 1', value: 'option-1' },
{ label: 'Option 2', value: 'option-2' },
]}
triggerLabel="More actions"
optionToString={(option) => option.label}
onButtonClick={() => {}}
onOptionClick={(option) => {}}
>
Disabled Action
</MultiActionButton>;Loading Indicator
The loading indicator replaces the button text to show a pending operation.
import MultiActionButton from '@camp/multi-action-button';
<MultiActionButton
loadingIndicator
options={[
{ label: 'Option 1', value: 'option-1' },
{ label: 'Option 2', value: 'option-2' },
]}
triggerLabel="More actions"
optionToString={(option) => option.label}
onButtonClick={() => {}}
onOptionClick={(option) => {}}
>
Loading
</MultiActionButton>;Menu Open
When the trigger button is clicked, a popover menu displays the additional action options.
import MultiActionButton from '@camp/multi-action-button';
<MultiActionButton
options={[
{ label: 'Option 1', value: 'option-1' },
{ label: 'Option 2', value: 'option-2' },
{ label: 'Option 3', value: 'option-3' },
]}
triggerLabel="More actions"
optionToString={(option) => option.label}
onButtonClick={() => {}}
onOptionClick={(option) => {}}
>
Primary Action
</MultiActionButton>;Usage
Best Practices
- Be consistent with button placement. In button groupings and modals, the primary button should be the furthest to the right.
- While our buttons do have a disabled state, disabling a button should be avoided as much as possible due to lack of keyboard focus and low contrast. Instead of disabling the button, consider showing a banner or helper text to communicate to the user the needed information.
- Use the
triggerLabelprop to provide an accessible label for the options trigger button (e.g. “More actions” or “More options”). - Use
optionToStringto tell the component how to convert option objects into display strings.
Options
The options prop accepts an array of any shape — the component does not enforce a specific object structure like { label, value }. Display text is always derived from your optionToString function, and the full option object is passed back to onOptionClick. The { label, value } shape used in examples matches the component’s Storybook stories, but any shape works as long as optionToString knows how to read it.
The only fields the component reads directly from an option are:
disabled— disables the menu item and blocks its click handlerrender— an optional per-option custom renderer that overridesdefaultOptionRenderer
// Any option shape works — just align optionToString with your data
const options = [
{ text: 'Copy', id: 'copy' },
{ text: 'Delete', id: 'delete', disabled: true },
];
<MultiActionButton
options={options}
triggerLabel="More actions"
optionToString={(option) => option.text}
onOptionClick={(option) => handleAction(option.id)}
onButtonClick={handlePrimary}
>
Save
</MultiActionButton>;Sizes
Buttons come in two sizes, the default medium size and a small size. Which size of the button to use is based on both the importance of the action as well as the context of where it is placed.
- Medium buttons are used for all primary page actions
- Small buttons are best suited for supplementary page actions
- Small buttons can also be used in the headers of other components where height is limited
- If in groups, button sizes should not be mixed
Content Guidelines
Button labels should be clearly and concisely written (no more than 3 words), in sentence case and with no punctuation at the end. Avoid unnecessary or ambiguous words, but include articles like “a” and “the,” as they provide clarity especially in translating. Use inclusive language that doesn’t discriminate from those who use assistive technology.
✅ DO
- Create a campaign
- Import a template
- Add a contact
- Add
🚫 DON’T
- Create New Campaign
- Import template
- Click here
- More
Accessibility
Keyboard Support
- Move focus to a button using the
tabkey, andtabagain to move to the dropdown arrow button (useshift+tabto move backwards) - When the button or dropdown button has keyboard focus, use the
spaceorenterkey to perform action - When the popover menu is open, use
↑or↓to navigate the additional options spaceorentercan also be used to select an option from the list in the popover- Press
escapeto close the popover menu - Arrow keys cycle through menu options — pressing
↓on the last option moves focus to the first, and pressing↑on the first moves focus to the last
ARIA Support
- The trigger button uses
aria-haspopup="true"to indicate it opens a menu - The trigger button uses
aria-expandedto communicate whether the menu is open or closed - Use the
triggerLabelprop to set an accessiblearia-labelon the trigger button