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.
| Keys | Does |
|---|---|
Enter / Space / โ (closed) | open the panel |
โ / โ | move the highlight, scrolling it into view |
Enter | select the highlighted option |
Esc | close |
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.
Search โ
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:
| Entry | Matches |
|---|---|
Nama | a top-level field |
Company.Name | a nested field |
Transaction.[1].Name | one array element |
Transaction.[*].Name | any 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(defaulttrue) opens the list upward when there isn't room below.shift(defaulttrue) 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.
| Variable | Default | Controls |
|---|---|---|
--mono-select-focus-color | --theme-primary | Focus / hover border (set by color) |
--mono-select-focus-rgb | primary rgb | Focus ring color (as r, g, b) |
--mono-select-underline-glow | 0 5px 6px -6px | Underlined focus glow geometry |
--mono-select-cursor-width | 3px | Keyboard-cursor bar on the highlighted option |
--mono-select-cursor-color | --mono-select-focus-color | Colour of that bar |
--mono-select-text | --theme-text | Trigger + label text color |
--mono-select-border | --theme-border | Trigger border color |
--mono-select-surface | --theme-surface | Dropdown / option surface |
--mono-select-background | --theme-background | Trigger background base |
--mono-select-shadow | 0 1px 2px โฆ | Trigger shadow |
--mono-select-dropdown-shadow | elevation preset | Dropdown popup shadow |
--mono-select-success | --theme-success | Valid-state color |
--mono-select-danger | --theme-danger | Invalid / required color |
--mono-select-warning | --theme-warning | Warning-state color |
Types โ
Import
import { SelectProps } from 'mono-helper'| Prop | Value | Default | Description |
|---|---|---|---|
modelValue | unknown | โ | The currently selected value. |
value | unknown | โ | Alias for the selected value, kept in sync with modelValue. |
items | string | SelectItem[] | โ | List of selectable items, as an array or JSON string. |
dataSource | SelectDataSource<SelectItem> | โ | DataSource used to drive the item list, taking precedence over items. |
immediate | boolean | โ | Auto-load the DataSource on attach when it has no items yet. |
loadMore | '' | 'button' | 'scroll' | boolean | โ | Incremental loading mode: scroll, button, or off. |
pageSize | number | โ | Chunk size used when paging a plain items array. |
keyValue | string | โ | Item property name used as the model value. |
displayValue | string | (item: SelectItem) => string | โ | Item property name or function used to derive display text. |
displayGroup | SelectDisplayGroup | โ | Per-level accessors for grouped options (header label per group level). |
groupKey | string | โ | Field holding a group node's key (default 'key'). |
groupItems | string | โ | Field holding a group node's child array (default 'items'). |
searchable | boolean | โ | Turn the field itself into a search input (combobox); server query when a DataSource is bound. |
searchValue | string | 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. |
searchOperation | string | โ | devextreme search operation for server search (default 'contains'). |
searchDebounce | number | โ | Debounce (ms) before a server search fires (default 300). |
searchPlaceholder | string | โ | Placeholder shown in the field while it is open/searching (falls back to `placeholder`). |
group | boolean | โ | Group a plain, paginated DataSource client-side (keeps scroll/load-more). |
groupSticky | boolean | โ | Keep group headers pinned to the top while their rows scroll. |
dropdownHeight | string | number | โ | Fixed height of the scrollable dropdown list. |
dropdownMaxHeight | string | number | โ | Maximum height of the scrollable dropdown list. |
stayOpen | boolean | โ | 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. |
label | string | โ | Text label shown above the select. |
placeholder | string | โ | Placeholder text shown when no value is selected. |
helperText | string | โ | Helper text shown below the select. |
validationState | 'warning' | 'default' | 'valid' | 'invalid' | โ | Validation state controlling the select's appearance. |
validationMessage | string | โ | Validation message shown below the select. |
errorMessage | string | โ | Error message shown below the select. |
successMessage | string | โ | Success message shown below the select. |
name | string | โ | Form field name submitted with the value. |
disabled | boolean | โ | Disables the select, preventing interaction. |
readonly | boolean | โ | Makes the select read-only, blocking value changes. |
required | boolean | โ | Marks the select as required and shows a required indicator. |
clearable | boolean | โ | Shows a clear button to reset the selected value. |
ariaLabelText | string | โ | Accessible label used when no visible label is present. |
ariaLabel | string | โ | โ |
width | string | 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.) |
height | string | number | โ | โ |
minWidth | string | number | โ | โ |
maxWidth | string | number | โ | โ |
minHeight | string | number | โ | โ |
maxHeight | string | number | โ | โ |
cssClass | SelectCssClass | โ | Custom CSS classes applied to internal select parts. |
visible | boolean | โ | Whether the control is shown. Defaults to `true`. |
visibleType | 'invisible' | 'none' | โ | How it hides when `visible` is `false`. Defaults to `'none'`. |