Skip to content

Select โ€‹

A dropdown picker built on a custom button + listbox UI. Sizes, color and visual variants, validation states, slot-overridable label/helper/prefix/suffix, and a clearable trigger. Toggle Vue / CSS to switch the live demo and source together.

Basic โ€‹

Default select with label, placeholder and helper text.

Vue SFC

Keyboard โ€‹

Opening highlights the first option, so โ†‘ / โ†“ start from a known place and Enter picks without needing an arrow press first. This works whether or not the select is searchable โ€” the trigger drives the list when there's no search field to hold focus.

KeysDoes
Enter / Space / โ†“ (closed)open the panel
โ†‘ / โ†“move the highlight, scrolling it into view
Enterselect the highlighted option
Escclose

The highlight is drawn as a leading bar on the option's left edge, distinct from the background that marks the selected option โ€” an option is often both at once. Tune it with --mono-select-cursor-width (default 3px) and --mono-select-cursor-color.

Sizes โ€‹

Small, medium and large.

Vue SFC

Variants โ€‹

outlined, filled and underlined.

underlined focuses with a soft glow under the line rather than a ring around the field โ€” tune it with --mono-select-underline-glow (default 0 5px 6px -6px).

Vue SFC

Colors โ€‹

All built-in color variants.

Vue SFC

States โ€‹

Disabled, readonly and required.

Vue SFC

Validation โ€‹

valid, invalid and warning states with messages.

Vue SFC

Clearable โ€‹

Clear button shown when a value is selected.

Vue SFC

Slots โ€‹

Custom label, helper and prefix/suffix content via slots.

Vue SFC

Event: change โ€‹

Listen to mno-change to react to selection.

Vue SFC

Event log โ€‹

Live log of mno-change and mno-clear events.

Vue SFC

Customized โ€‹

Override per-element styling with cssClass (Vue) or utility classes (CSS).

Vue SFC

Custom keys โ€‹

Use key-value and display-value to feed natural-shape items (for example { id, name }) without pre-mapping. key-value names the property stored in modelValue; omit it to store the whole item object. display-value is either a property name (string) or a (item) => string function โ€” when unset it falls back to item.label.

Without key-value the whole item is the value, and it is matched by identity โ€” the object in modelValue has to be one of the objects in items. A reactive wrapper around it is fine (the select compares raw targets), but an item rebuilt between renders โ€” a refetch, a structuredClone, a JSON round trip โ€” is a different object and stops resolving. Pass key-value whenever items are re-created.

Vue SFC

DataSource (devextreme) โ€‹

Bind a live devextreme DataSource with :data-source.prop. The select reads its items and stays reactive to the source's events โ€” so an external ds.filter(...) + ds.load() updates the list with no re-binding. With load-more="scroll" it pages the source one chunk at a time (here pageSize: 5). This example builds the source with mono-utils' monoCreateFetcher against a public OData endpoint (baseUrl, no configBaseUrl). Bind with .prop and use key-value / display-value to map the server fields.

Add searchable and the trigger becomes a text box you type into โ€” with a bound DataSource it queries the server (debounced, search-value names the fields), otherwise it filters the items array client-side. search-operation picks the comparison (default contains), search-debounce the delay (default 300 ms) and search-placeholder the hint shown while open.

Search expressions โ€‹

search-value is not limited to top-level field names. It takes the same grammar the data grid uses, as an array or as a comma-separated string โ€” the two are equivalent, so plain HTML loses nothing:

html
search-value="Company.Name,Transaction.[*].Price,*.[*].*"
ts
:search-value.prop="['Company.Name', 'Transaction.[1].Name', 'Transaction.[*].Price', '*']"

An entry can be:

EntryMatches
Namaa top-level field
Company.Namea nested field
Transaction.[1].Nameone array element
Transaction.[*].Nameany element of the array
*every top-level field
Company.*every field of Company
*.*every field of every nested object
*.[*].*every field of every array element

Patterns read literally, segment by segment โ€” '*' covers the top level only, so pair it with '*.*' / '*.[*].*' to reach deeper. A field named explicitly always wins over a pattern, in either order, and is searched exactly once.

In the array form an entry may also be a { field, custom } clause builder, for a column contains can't search โ€” a boolean, or a code the user never types. Return null to opt the column out of a given term:

ts
:search-value.prop="[
  '*',
  { field: 'Active', custom: ({ field, value }) => `${field} eq ${value === 'yes'}` },
]"

Setting search-value explicitly means it alone decides what is searched.

Leave it off and the default is '*' โ€” every top-level field of an option โ€” so searching works without naming anything. display-value (when it's a string) and key-value stay in the list beside it, and the rendered display text is matched too, which is the only way to search a display-value function.

Two caveats on a bound DataSource: a * pattern is resolved against the rows already loaded, so it can only see fields present in that sample; and it only emits clauses for string columns, because contains(Price,'x') is not valid OData. That is exactly why display-value / key-value remain alongside '*' โ€” they are explicit entries, so they still work before the first page arrives and a numeric key-value stays searchable. Give any other non-text column an explicit entry or a custom builder.

To offer no search at all, drop searchable rather than emptying search-value.

Vue SFC

Grouped options โ€‹

display-group is an array with one accessor per level (string field or function), used as the group key and header. Add the boolean group to bucket a paginated source client-side, or feed pre-grouped { key, items } data directly; group-sticky pins headers.

Two levels over a 1,200-row static array, load-more="scroll" revealing a chunk at a time.

Pre-grouped data with custom group-key / group-items field names.

Width & height โ€‹

Set width, height, min-width, max-width, min-height or max-height โ€” each takes a CSS string ("260px", "80%") or a number (px). This sizes the field (distinct from dropdownHeight/dropdownMaxHeight, which size the popup).

Vue SFC

Placement โ€‹

The dropdown keeps itself inside the viewport, so a select near the bottom of the page is never clipped:

  • flip (default true) opens the list upward when there isn't room below.
  • shift (default true) slides it horizontally so it doesn't overflow a screen edge.
  • When neither side fits the full list, it opens on the roomier side and shrinks to fit, scrolling internally. This caps dropdownHeight / dropdownMaxHeight โ€” those stay the requested size whenever there is room for them.

Set :flip="false" / :shift="false" to pin the list below the field.

CSS Variables โ€‹

Vue SFC

Themed through --mono-select-* custom properties (they inherit and pierce the shadow boundary); an explicit --mono-select-focus-color override wins over the color prop. Re-skin globally via the --theme-* tokens.

VariableDefaultControls
--mono-select-focus-color--theme-primaryFocus / hover border (set by color)
--mono-select-focus-rgbprimary rgbFocus ring color (as r, g, b)
--mono-select-underline-glow0 5px 6px -6pxUnderlined focus glow geometry
--mono-select-cursor-width3pxKeyboard-cursor bar on the highlighted option
--mono-select-cursor-color--mono-select-focus-colorColour of that bar
--mono-select-text--theme-textTrigger + label text color
--mono-select-border--theme-borderTrigger border color
--mono-select-surface--theme-surfaceDropdown / option surface
--mono-select-background--theme-backgroundTrigger background base
--mono-select-shadow0 1px 2px โ€ฆTrigger shadow
--mono-select-dropdown-shadowelevation presetDropdown popup shadow
--mono-select-success--theme-successValid-state color
--mono-select-danger--theme-dangerInvalid / required color
--mono-select-warning--theme-warningWarning-state color

Types โ€‹

Importimport { SelectProps } from 'mono-helper'
PropValueDefaultDescription
modelValueunknownโ€”The currently selected value.
valueunknownโ€”Alias for the selected value, kept in sync with modelValue.
itemsstring | SelectItem[]โ€”List of selectable items, as an array or JSON string.
dataSourceSelectDataSource<SelectItem>โ€”DataSource used to drive the item list, taking precedence over items.
immediatebooleanโ€”Auto-load the DataSource on attach when it has no items yet.
loadMore'' | 'button' | 'scroll' | booleanโ€”Incremental loading mode: scroll, button, or off.
pageSizenumberโ€”Chunk size used when paging a plain items array.
keyValuestringโ€”Item property name used as the model value.
displayValuestring | (item: SelectItem) => stringโ€”Item property name or function used to derive display text.
displayGroupSelectDisplayGroupโ€”Per-level accessors for grouped options (header label per group level).
groupKeystringโ€”Field holding a group node's key (default 'key').
groupItemsstringโ€”Field holding a group node's child array (default 'items').
searchablebooleanโ€”Turn the field itself into a search input (combobox); server query when a DataSource is bound.
searchValuestring | MonoSearchExprEntry[]โ€”Field(s) the search matches (server query + client filter target). A comma string or an array; entries may be plain columns, paths (`Company.Name`, `Transaction.[*].Price`), `*` patterns (`'*'`, `'*.[*].*'`) or, in array form, `{ field, custom }` clause builders.
searchOperationstringโ€”devextreme search operation for server search (default 'contains').
searchDebouncenumberโ€”Debounce (ms) before a server search fires (default 300).
searchPlaceholderstringโ€”Placeholder shown in the field while it is open/searching (falls back to `placeholder`).
groupbooleanโ€”Group a plain, paginated DataSource client-side (keeps scroll/load-more).
groupStickybooleanโ€”Keep group headers pinned to the top while their rows scroll.
dropdownHeightstring | numberโ€”Fixed height of the scrollable dropdown list.
dropdownMaxHeightstring | numberโ€”Maximum height of the scrollable dropdown list.
stayOpenbooleanโ€”Exempt this select from every automatic close โ€” clicking or focusing anything outside it, which includes opening another select. Not a lock: its own trigger, Escape and picking an item still close it. Set it on every select to allow several dropdowns open at once.
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'โ€”Visual size of the select.
color'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info'โ€”Color theme applied to the select.
variant'underlined' | 'outlined' | 'filled'โ€”Visual style variant of the select.
labelstringโ€”Text label shown above the select.
placeholderstringโ€”Placeholder text shown when no value is selected.
helperTextstringโ€”Helper text shown below the select.
validationState'warning' | 'default' | 'valid' | 'invalid'โ€”Validation state controlling the select's appearance.
validationMessagestringโ€”Validation message shown below the select.
errorMessagestringโ€”Error message shown below the select.
successMessagestringโ€”Success message shown below the select.
namestringโ€”Form field name submitted with the value.
disabledbooleanโ€”Disables the select, preventing interaction.
readonlybooleanโ€”Makes the select read-only, blocking value changes.
requiredbooleanโ€”Marks the select as required and shows a required indicator.
clearablebooleanโ€”Shows a clear button to reset the selected value.
ariaLabelTextstringโ€”Accessible label used when no visible label is present.
ariaLabelstringโ€”โ€”
widthstring | numberโ€”Explicit sizing of the field. Each accepts a CSS length string (`"320px"`, `"80%"`) or a number (interpreted as px). Use `width="100%"` for full width. (Distinct from `dropdownHeight`/`dropdownMaxHeight`, which size the popup.)
heightstring | numberโ€”โ€”
minWidthstring | numberโ€”โ€”
maxWidthstring | numberโ€”โ€”
minHeightstring | numberโ€”โ€”
maxHeightstring | numberโ€”โ€”
cssClassSelectCssClassโ€”Custom CSS classes applied to internal select parts.
visiblebooleanโ€”Whether the control is shown. Defaults to `true`.
visibleType'invisible' | 'none'โ€”How it hides when `visible` is `false`. Defaults to `'none'`.