Skip to content
SproutAceve · v3.31.0
Overview What is your role? Connect to Sprout MCP reference Adopting Sprout
Brand & logos Color Typography Spacing & layout Elevation Iconography Accessibility
Overview Alert Avatar Badge Breadcrumb Buttons Cards Checkbox Data grid Dialog Dropdown button Fab button Floating tabs Inputs Menu Navigation Numeric input Progress bar Progress ring Radio button Ribbon toolbar Switch Tabs Tag Tooltip
Interaction & motion Voice & content Product patterns
AI patterns AI transparency & disclosure AI disclosure label
Design principles Personas Trust and ethics Meet the makers
Build the systemplay Tower of tokensplay Site runnerplay
How it works Changelogv3.31 Roadmap Contribute
Components

Dropdown button.

A button whose entire face — label and chevron together — opens an attached menu of closely related actions. One control, one hit target, no separate chevron zone. Use it when a single action has two or three named variants people need often enough to keep one click away, not as a catch-all for unrelated commands.

Try it

Space / Enter / ↓ opens the menu — try it with a keyboard.
Size
Style

Anatomy

One control. No divider, no second hit target — the chevron is decoration that signals a menu, not an independent button.

Save changes
LabelThe default action, verb + noun, same copy rules as Buttons. Always present — never chevron-only.
Chevronchevron-down, trailing, scales with size (12/14/16px). Rotates 180° while the menu is open — the only state the chevron carries on its own.
Hit targetThe whole control: label, gap and chevron are one button element. Clicking anywhere, including directly on the chevron, opens the same menu.
Attached menuOpens directly below, left-aligned to the trigger, 6px gap. Same surface as Context menu — see /menu — border, shadow-pop and padding all reused, not reinvented.

Size

Three sizes, identical heights to Buttons (28/38/48px) — a Dropdown button lines up with a Button next to it.

Dropdown Small 28px
Dropdown Medium 38px
Dropdown Large 48px

Style & states

Filled, Border and Borderless, each across Default, Hovered, Pressed and Disabled — the full matrix from the Figma component.

FilledBorderBorderless
defaultDropdown Dropdown Dropdown
hoverDropdown Dropdown Dropdown
pressedDropdown Dropdown Dropdown
disabledDropdown Dropdown Dropdown

No semantic Type axis exists for this component — unlike Buttons (primary/neutral/success/danger), Filled Dropdown button is always the accent green. If a danger or success variant turns out to be needed (e.g. a destructive action with alternatives), that is new scope for the Figma file, not something this page should invent.

The attached menu

Menu items are the Context menu component (/menu) — same surface, same row anatomy, same do/don't rules for labels and icons. This page only covers the trigger and the keyboard model specific to it.

Save as draft
Save and close
Save as template
ContentNamed variants of the trigger's own action — alternate ways to do the same thing. Not a place for unrelated commands; that belongs in Context menu instead.
OrderMost-used variant first. The single most common action of all belongs on the trigger's own face, never buried as the first menu item.
LengthTwo to four items. Past that, the trigger is hiding too much — reconsider the flow instead of growing the list.

Do & don't

Send invoice
Do — put the single most common action on the trigger's own face. "Send invoice" is the default; the menu holds "Send and mark as paid", "Send a reminder later".
Options
Don't — hide the one thing people do every time behind a generic label. If "Options" is doing the work, the menu — not the button — became the real control.
Save changes
Do — use it for variants of one action: Save / Save as draft / Save and close.
File actions
Don't — use it as a catch-all for unrelated commands (rename, export, delete). That is Context menu's job — see /menu.

Specification

Every value is a token, ported from the Figma component.

Height28 / 38 / 48px — Small / Medium / Large, same as Buttons
Corner radius4px — var(--radius-2). Lower than Buttons' 8px; not yet reconciled with the Buttons spec.
LabelManrope Semibold 12 / 14 / 16px
Chevronchevron-down, 12 / 14 / 16px, trailing, rotates 180° open
Label-to-chevron gap8 / 12 / 16px — space-xs / s / m
Filled — default / hover / pressedvar(--accent) / var(--accent-hover) / var(--accent-deep), label var(--accent-ink)
Border — default / hover / pressedvar(--canvas) / var(--surface-2) / var(--line), 1px var(--line-strong) border, label var(--ink-1)
Borderless — default / hover / pressedtransparent / var(--surface-2) / var(--line), label var(--ink-1)
DisabledFilled: var(--ink-6) fill, var(--line) label. Border/Borderless: var(--ink-6) label, var(--ink-6) border (Border only)
Attached menuSame surface as Context menu: var(--radius-2), var(--shadow-pop), 6px padding, 6px gap below the trigger

Accessibility

The W3C APG 'menu button' pattern — one activatable control, a menu it owns, and a documented keyboard model.

ElementA real <button>, never a <div> — keyboard and screen readers work by default for the trigger itself.
aria-haspopup="menu"On the trigger at all times, so assistive tech announces that activating it opens a menu.
aria-expandedtrue while the menu is open, false while closed — kept in sync with visible state, never just visual.
Space / EnterActivates the trigger and opens the menu.
Arrow Down (on trigger)Opens the menu and moves focus to the first item.
Arrow Up (on trigger)Opens the menu and moves focus to the last item — lets a keyboard user reach the bottom item without stepping through every row.
Arrow Down / Up (in menu)Moves focus to the next / previous item, wrapping at the ends.
Home / EndJumps focus to the first / last item.
EscapeCloses the menu and returns focus to the trigger — focus must never land on the page body.
Outside clickCloses the menu without moving focus.
DisabledRemoved from the tab order; never disable the trigger to explain a missing precondition — say why next to it instead.

Props (React)

Proposal — no React primitive ships yet. This is the target shape, not an import.

type DropdownButtonProps = {
  size?: "s" | "m" | "l";                         // 28 / 38 / 48px, default "m"
  style?: "filled" | "border" | "borderless";      // default "border"
  disabled?: boolean;
  label: ReactNode;                 // the default action — verb + noun
  items: Array<{
    label: ReactNode;
    onSelect: () => void;
    disabled?: boolean;
  }>;                                // 2-4 named variants of the default action
};
← PreviousDialogNext →Fab button
Sprout · Aceve Design System · v3.31.0
Figma library GitLabReleases