Design system Inputs
Dropdown
A field that reads and changes one stored value or a compact set. Long closed sets may filter directly through the same dropdown face.
.mk-select-face
Overview
The dropdown is a menu button dressed as the field it is: it shows its value and changes it. The value renders as what the product wears for it — a status shows its pill, a plain value shows text — and the trailing filled triangle flips while the attached list is open. Press it.
Usage
- Select a stored value from a closed setThe field shows the current value and opens the available options. Use Search instead when choosing a result should navigate rather than populate a field.
- Use Multi-select for a compact value setEvery selected value remains visible in the field and carries its own removal control. When a long closed set needs filtering, use the Searchable dropdown variant.
- Preserve the value's visual meaningWhen the selected value has a defined label treatment, keep that treatment in the closed field and in the option list.
Anatomy
- 1The face. White always, the strong grey edge, control radius, M height like every field — it shipped S once and the family never sat on one line.
- 2Value area. A placeholder occupies this seat until a choice is made; afterwards the selected value replaces it. A status value arrives as its own pill.
- 3Trailing chevron. Filled, 20px, trailing. It flips while the menu is open — the openness is visible from the control itself.
Variants and states
The size ladder
Shared with the input and the date field — .mk-ctl-s / -m / -l, so a
mixed row of controls sits on one line to the pixel. Dense rows opt into S.
States
Every state below is the real component wearing that state, not a picture of it.
| State | Specimen | What changes |
|---|---|---|
| Rest | White face, the strong grey edge — the same resting dress on every ground; the warm resting variant is a retired no-op. | |
| Hover | The border warms to the accent hairline; the fill stays white — one interaction voice for the whole field family. | |
| Keyboard focus | The standard 2px camel outline at 2px offset. | |
| Open | The attribute says expanded: the border warms, the engaged ring appears and the triangle flips — openness is visible from the control itself. | |
| Empty | An unchosen dropdown rests on a muted ask — a placeholder value in the quiet voice, never a blank. | |
| Blocked | The whole face fades and the press refuses; the value stays readable in place. |
Multi-select dropdown
The multi-select dropdown wears its chosen values as chips inside the face — the filter-chip component, each removable by its own cross without opening the list. The face grows by wrapping, never by hiding the choice behind a count. In the open list a chosen option keeps the selection fill and stays in place: choosing does not close a multi list.
Searchable dropdown
Past roughly seven options the same dropdown face becomes editable. Typing filters its closed set; choosing a result commits that value and returns the face to its ordinary closed state. It is not the Search component: there is no magnifier, clear action, or second field inside the panel.
Choosing a status
A status arrives in the list the same way it rests in the face: as its own pill. The open list is the status's whole vocabulary, and the option being left is marked chosen — the agent sees where the object stands while choosing where it goes.
- Changing a stateA dropdown that changes an object's state keeps the confirm step: the list swaps to the sentence naming the object and the destination before committing.
- The phone stretches the faceFull width in the row; the list stays attached — a chevron never answers with a bottom sheet.
Do and don't
The status wears its own pill inside the face — one face for the status everywhere, whether it rests or chooses.
The same status as bare text makes the value's kind invisible — the agent reads the word twice to learn it is a state.
Copy
- The value verbatimThe face shows the chosen value as the product writes it — nothing prepended.
- Options carry consequencesA choice with a cost says it in its own note line inside the menu, before the press.
- The empty ask is quietA muted "Choose …" in the value's own vocabulary.
Accessibility
- The control declares its popupThe standard face uses
aria-haspopupandaria-expanded. The Searchable dropdown uses an editablecomboboxwitharia-autocomplete="list"and owns the same attached listbox. - The name includes the valueRead together: what this chooses and what is chosen now.
- The triangle is decorationThe attribute carries the openness; the flip only draws it.
When to reach for something else
- Free entryUse Text input — the dropdown's shape promises a closed list.
- Find a destination without setting a field valueUse Search; Search results navigate or reveal records, while a Searchable dropdown commits one value from its closed set.
- Acting, not choosingUse the Split button; a dropdown never performs.
- How a value is writtenUse the Unit toggle.
Markup
<span class="mk-menu-wrap">
<button class="mk-select-face" type="button"
aria-haspopup="menu" aria-expanded="false">
<span>Selected value</span>
<svg class="caret" data-mk-icon="caret" aria-hidden="true"></svg>
</button>
<div class="mk-menu" role="menu" aria-label="Options" hidden>
<button class="mk-menu-item" role="menuitem" type="button">First option</button>
</div>
</span>
<!-- multi: chips in the face, a listbox that stays open while choosing -->
<span class="mk-menu-wrap">
<button class="mk-select-face mk-select-multi" type="button"
aria-haspopup="listbox" aria-expanded="false">
<span class="mk-chip">First value
<svg class="mk-chip-x" data-mk-icon="close" aria-hidden="true"></svg></span>
<svg class="caret" data-mk-icon="caret" aria-hidden="true"></svg>
</button>
<div class="mk-menu" role="listbox" aria-multiselectable="true"
aria-label="Options" hidden>
<ul class="mk-optlist">
<li><button class="mk-opt" role="option" aria-selected="true" type="button">
<span class="mk-opt-main"><span class="mk-opt-name">First value</span></span>
</button></li>
</ul>
</div>
</span>
<!-- searchable: the dropdown face itself accepts the filtering query -->
<span class="mk-menu-wrap">
<span class="mk-select-face mk-select-searchable is-open">
<input class="mk-select-query" type="text" role="combobox"
aria-autocomplete="list" aria-expanded="true"
aria-controls="available-values" autocomplete="off">
<svg class="caret" data-mk-icon="caret" aria-hidden="true"></svg>
</span>
<div class="mk-menu" role="listbox" aria-label="Available values">
<ul class="mk-optlist" id="available-values">…</ul>
</div>
</span>