Dropdowns

Dropdown

A menu that opens from a trigger and holds a list of choices or actions.

Refined portVue source: WildDropdown.vueStorybook story: Dropdowns/DropdownReact component: WDropdown, WDropdownMenu

Dropdown pill

A compact filter that opens a menu, used to build filter bars.

Live React portVue source: WildDropdownPill.vueStorybook story: Dropdowns/Dropdown Pill

Advanced multi-select

Picks many items from a large, grouped list, with search, select-all and a running count.

Live React portVue source: WildAdvancedMultiSelectDropdown.vueStorybook story: Dropdowns/Advanced Multi-Select

Try it

Search for “bore”, then tick one site in a group and watch its group and client go mixed.

Size
Chips
Disabled
<WildAdvancedMultiSelectDropdown
  v-model="chosen"
  :nodes="sites"
/>

When to use

  • Use it to choose many sites from a list grouped by client and group.
  • Use it when people pick whole groups at once, such as every site a client owns.
Don’t use it
  • For a flat list, or a single choice. Use Search select.
  • For a few options that should all stay visible. Use Checkbox.

Anatomy

  • Trigger: the placeholder, a count of selected sites, or the select-all label.
  • Search: filters as you type, and opens each match’s client and group.
  • Select all: ticks or clears every site.
  • Tree: clients, groups and sites, each with a checkbox.
  • Chips: one per top-level client or site with a selection, each removable.

Selection

Ticking a client or group ticks every site under it. When only some are ticked, its box shows mixed, and so does Select all.

Orchard Holdings · 2/5Canterbury Ag
<WildAdvancedMultiSelectDropdown v-model="chosen" :nodes="sites" />
A fully selected client shows as a blue chip. A part-selected one counts its own sites, here 2/5.

Sizes

Three heights. The default is sm, at 36px.

sm · 36
md · 40
lg · 44
<WildAdvancedMultiSelectDropdown :nodes="sites" />
<WildAdvancedMultiSelectDropdown size="md" :nodes="sites" />
<WildAdvancedMultiSelectDropdown size="lg" :nodes="sites" />

States

Disabled dims the trigger to 40% and locks its chips.

none
some
all
disabled

Content

  • Name the items in placeholder and allItemsLabel when they aren’t sites.
  • Keep labels short. Long ones end in an ellipsis.

Accessibility

The trigger announces the summary it shows. Each tree row announces its level and whether it’s checked, unchecked or mixed.

KeyWhat it does
Enter / SpaceOn the trigger, opens or closes the panel. On Select all or a row, ticks or clears every site it covers.
TabMoves through search, Select all and the tree. Tabbing out closes the panel.
↓ / ↑Moves between visible rows, and ↓ from the search into the tree.
→Opens a client or group, or moves to its first child.
←Closes a client or group, or moves to its parent.
Home / EndFirst or last visible row.
EscapeCloses the panel and returns focus to the trigger.

Props

PropTypeDefaultDescription
nodesTreeNode[]—{ id, label, children? }, nested to any depth.
v-modelSelectionOutput—The ticked sites: { mode, selectedNodeIds, selectedLeafIds }.
placeholderstring'Select sites...'Trigger text when nothing is selected.
allItemsLabelstring'All Sites'Select-all row, and the trigger when all are selected.
size'sm' | 'md' | 'lg''sm'Trigger height: 36, 40 or 44px.
showChipsbooleantrueShows the chips under the trigger.
maxHeightnumber400Height cap on the whole panel, in px.
disabledbooleanfalseDims the trigger and locks its chips.
virtualizedbooleanfalseReserved for long lists. Has no effect yet.
@change(value: SelectionOutput) => void—Fires with the new selection on every tick.
@open / @close() => void—When the panel opens or closes.

Tokens

TokenValueWhere it lands
--radius-xl10pxTrigger and search corners.
--radius-lg8pxPanel corners.
--radius-md6pxRow corners.
--color-border-default#E6E6E6Borders at rest, and the panel dividers.
--color-grey-800#7F7D83Trigger border on hover, and chevrons.
--color-grey-200#F1F1F1Trigger fill on hover.
--color-grey-100#F5F5F5Row fill on hover.
--color-primary-active#1877F2Open border and keyboard focus ring.
--color-primary-light#EBFAFFSelect all, once everything is selected.
--global-blue-1100#0C296ASelect all text on that fill, 12.75:1 (blue-1000 would be 3.96:1).
--color-grey-1100#1D1C20Row and value text.
(no token)#4F4D55Placeholder and no-match text.
--shadow-dropdown0 4px 12px rgba(0,0,0,.08), …Panel elevation.

Search select

A select you can type into, for lists too long to scan by eye.

Refined portVue source: WildSearchSelect.vue

Try it

Open it and type “ohau” or a client’s name. The list holds 120 sites.

Site
Search by site or client.
Selection
Size
Error
Disabled
<WildSearchSelect
  v-model="siteId"
  label="Site"
  placeholder="Select site"
  search-placeholder="Search sites or clients"
  help="Search by site or client."
  :options="sites"
/>

When to use

  • Use it for lists too long to scan, such as sites or clients.
  • Use multiple when more than one choice is allowed.
  • Add meta to each option when names repeat across clients.
Don’t use it

Anatomy

A label and hint, the trigger, and a panel: a search row, rows with their meta, and a count line when the list is cut short.

Site120 sites
Bore 1Emu Park Orchards
Bore 2Blenheim Vineyards
Bore 3Kaituna Water Scheme
Bore 4Martinborough Estates
Bore 5Te Puke Kiwifruit
Bore 6Pukekohe Fresh
Showing the first 6 of 31 matches. Keep typing to narrow.

Multiple selection

Rows become checkboxes and the panel stays open. Choices show as chips, or as the first and a +N badge when space is tight.

Bore 12North PumpTank 3 — Woolshed
chips
+N badge

Sizes

The same heights as Select. The rows grow with the field.

sm · 36
lg · 44

States

Site
Choose a site to continue.
error
Site
disabled
Client
Site
Pick a client and the site list unlocks with its sites.

Content

  • Label it with a noun: Site, Client.
  • Write the placeholder as Select plus the noun: Select site.
  • Make disabledText say what unlocks the field: Choose a client first.
  • Keep meta short. A long one is cut off to fit.

Accessibility

The trigger announces its label and value. Opening focuses the search, and a screen reader follows the highlight and hears the count as you type.

KeyWhat it does
Enter / Space / ↓ / ↑On the trigger, opens the list.
A letterOn the trigger, opens it already searching.
↓ / ↑Moves the highlight. Wraps and skips unavailable rows.
Page Down / Page UpMoves the highlight eight rows.
EnterChooses the highlighted row. In multiple, ticks or unticks it and stays open.
Escape / Alt + ↑Closes the list, focus back on the trigger.
TabCloses the list and moves on.
Backspace / DeleteOn a chip’s cross, removes that choice.

Props

PropTypeDefaultDescription
v-modelstring | string[] | null—The choice, or choices with multiple.
options{ value, label, meta?, disabled? }[]—The choices. Meta is searched too.
labelstring—The field’s visible name.
ariaLabelstring—Accessible name without a visible label.
placeholderstring'Select option'Trigger text before anything is chosen.
requiredbooleanfalseAsterisk on the label; announced as required.
multiplebooleanfalseAllows more than one choice.
errorboolean | string—A string is shown as the message.
disabledbooleanfalseCan’t be opened or tabbed to.
disabledTextstring—Trigger text while disabled.
maxDisplayItemsnumber50Rows listed before the count line.
size'sm' | 'lg''sm'Height: 36 or 44px.
showChipsbooleantrueMultiple only: chips, or first choice and +N.
hintstring—Short context beside the label.
helpstring—Guidance under the field.
searchPlaceholderstring'Search'Placeholder in the search row.
noMatchTextstring'Nothing found'Shown when nothing matches.
namestring—Posts the value with a form.

Tokens

TokenValueWhere it lands
--radius-lg8pxTrigger and panel corners.
--global-neutral-grey-600#DCDCDETrigger border at rest.
--global-neutral-grey-800#ADACB0Trigger border on hover.
--global-blue-1000#1877F2Focused or open edge, the tick, Clear all.
--color-error#E12121Trigger edge on error.
--global-neutral-grey-500#E6E6E6Panel edge, disabled border.
--global-neutral-grey-300#F1F1F1Highlighted row.
--global-neutral-grey-200#F5F5F5Disabled ground.
--global-neutral-grey-400#ECECEDDividers inside the panel.
--global-neutral-grey-1000#4F4D55Placeholder, meta, count line.
--shadow-dropdown0 4px 12px rgba(0,0,0,.08), 0 2px 4px rgba(0,0,0,.04)The open panel.

Icon menu

A menu hung off one icon button, for the actions on a table or list row.

Refined portVue source: WildIconMenu.vueReact component: WIconMenu, KebabGlyph

Try it

Open it with a click or the arrow keys, then pick an action.

Nothing picked yet
Size
Row icons
Disabled
<WildIconMenu
  name="kebab"
  aria-label="Actions for Alarm 1"
  size="md"
  :options="alarmActions"
  @select="onAction"
/>

When to use

  • Use it for the actions on one row of a table or list, such as an alarm.
  • Use it where a row has no room for labelled buttons.
Don’t use it
  • For the main action on a page. Use a Button.
  • For one or two actions. Show them as Icon buttons.
  • To choose a value. Use a Select.

Anatomy

An icon button and a dropdown menu. The menu opens 6px below, aligned to the trigger’s right edge.

Edit
History
Delete
open
The trigger keeps its pressed look while the menu is open. Near the bottom of the window the menu opens above instead.

Sizes

Three square triggers. The default is md, at 28px.

sm · 24
md · 28
lg · 32

Content

  • Keep each action to a word or two: Edit, History, Delete.
  • Name the object only when the action alone is ambiguous.
  • Put destructive actions last.
  • Name the row in the trigger’s label: Actions for Alarm 1.

Accessibility

The trigger is a menu button, so a screen reader hears its label and that it opens a menu. Pass ariaLabel.

KeyWhat it does
Enter / SpaceOn the trigger, opens the menu on the first action. On an action, runs it.
Down / Up arrowOn the trigger, opens on the first or last action. In the menu, moves between actions.
Home / EndMoves to the first or last action.
A letterMoves to the next action starting with it.
EscapeCloses the menu and returns focus to the trigger.
TabCloses the menu and moves on.

Props

PropTypeDefaultDescription
namestring—Trigger icon name. Use a kebab for row actions.
options{ Id, Name, Icon? }[][]The actions, in order. The refined menu adds Destructive and Disabled.
ariaLabelstring'Menu'Accessible name for the trigger.
size'sm' | 'md' | 'lg''md'Trigger size: 24, 28 or 32px.
iconClassstring'h-4 w-4 …'Classes on the trigger icon: 16px, grey.
disabledbooleanfalseBlocks the trigger, so the menu never opens.
menuClassstring'w-44'Menu width. The default is 176px.
portalbooleantrueRenders the menu on the body, above clipping tables.
@select(option) => void—Fires with the picked action.
@open-change(open: boolean) => void—Fires when the menu opens or closes.

Tokens

TokenValueWhere it lands
--global-neutral-grey-900#7F7D83Trigger icon at rest.
--global-neutral-grey-1200#1D1C20Trigger icon on hover.
--global-neutral-grey-300#F1F1F1Trigger and row hover.
--global-neutral-grey-400#ECECEDTrigger ground while pressed or open.
--global-neutral-grey-800#ADACB0Disabled trigger icon and row text.
--global-blue-1000#1877F2Trigger icon while open; focus ring.
--global-neutral-grey-500#E6E6E6Menu border.
--global-cool-grey-1200#24262BAction text.
--global-cool-grey-900#595E6ARow icons.
--global-red-900#BC1C1CDestructive action text.
--global-red-100#FEEBEBDestructive row hover.
--shadow-dropdown0 4px 12pxMenu elevation.

Link popup

A table link that opens related detail in a shared popup window, so the list keeps its place.

Refined portVue source: WildLinkPopup.vueReact component: WLinkPopup