Select

Demo
Searchable

Default

<RSelect /> is base component which will have <ROption /> as default slot. value of each item will be on value prop of ROption.

Custom Option

Default slot of ROption components lets you render your custom item. by default only text prop is shown. If you do not pass text prop you need to use renderPlaceholder to customize the placeholder and if select is multiple you should use custom selected items ( tags ) as well.

single item
multiple item

Custom Placeholder

If you don't specify text on ROption you need to use a custom placeholder which is a function accepting selected option( when single select ) or array of selected options( when multiple select ) and returns a string to be displayed when any item is selected. defaults to:

renderPlaceholder: (option: Option | Option[]) => {
  if (Array.isArray(option)) return `${option.length} selected`
  else return option.text || ''
}

Custom Selected Items

To show custom tags when selection is multiple you can use named slot of #selectedItem which accepts option props. context prop is used for passing custom data.

Custom Selected Items

By default searchable prop does search over text prop of ROption. If you don't pass text or want a different type of searching you can use customSearch prop which is a function and is called whenever the input changes accepting search query as it's parameter.

Async items

Here is an example of using items that are fetched from an api. noDropdownOnEmptySearch hides dropdown when there is no search query.

There are some cases where some options are pre-selected ( for example inital value of v-model is not empty ) but you don't have the list yet or values you have as initial modelValue are not on the list of your options, in this case you can use exposed method of setSelectedItems to pass the items to RSelect. The first parameter is the array of objects as you would pass props to ROption.
this method does NOT modify v-model, it just updates selected items if there are any missing from options.
<RSelect ref="selectRef">...</RSelect>
import { RSelect } from 'sevue'
const selectRef = ref<InstanceOf<typeof RSelect> | undefined>()

// letting rselect know of items that are selected but are not on options list:
selectRef.value.setSelectedItems([
  {
    value: item.id // mandatory
    context: {} // to pass custom data you can later use for custom templating
  }
])

RSelectGroup

Used when items are grouped.

Multiple

Initial value of v-model or modelValue needs to be an array. keepOpenAfterSelection prevents the select from closing after value selection.

Disabled

This prop can be passed to RSelect to disable the whole select or ROption to disable specific option/options.

Optimized items

You might experience some lags when there are lots of items in your options list. You can optimize rendering of items using the method below:

You need to pass the main array of items to items prop of RSelect: <RSelect :items="myLongList" />. doing so you get a prop in default slot of RSelect called optimizedItems. you shall use this prop for rendering your list instead of myLongList.

items array must have value key in each item which is mandatory for setting values if not you can use itemExtractor prop. it recieves item as it's first parameter and must return an object containing at least value which will be used as value prop for ROption. this is equalant to passing props to ROption.

<template>
  <RSelect :items="myLongList" :itemExtractor="itemExtractor">
    <template #default="{ optimizedItems }">
      <ROption v-for="item in optimizedItems" :value="item.id" :text="item.title" />
    </template>
  </RSelect>
</template>

<script setup>
const itemExtractor = (item) => {
  return {
    ...item,
    value: item.id,
  };
};
</script>
Select with 10k items

Controlling the optimized list

The list you receive as optimizedList is being filtered based on a page state which is being increased each time user reaches end of the dropdown list. to customize the parameters you can use perPage and paginationOffset props. both are numbers and default to 10 (page) and 40 (paginationOffset)

Usage for grouped items

When you items are grouped ( for example Country[].City[] ) you can still use paginated list with same props described earlier plus you also need to speicfy itemsKey (default: 'items') and groupIdentifier (default: 'id'). itemsKey is the key where the nested items are located and groupIdentifier is the key to a property which is unique to each group. For example if we want to use in the following example as select items

[
  {
    title: "UK",
    cities: [
      { name: "London", id: 1 }, { name: "Bristol", id: 2 }
    ],
  },
  {
    title: "Russia",
    cities: [
      { name: "Moscow", id: 3 }, { name: "Saint Petersburg", id: 4 }, { name: "Novosibirsk", id: 5 }
    ],
  },
]

we should pass itemsKey="cities" and groupIdentifier="title". so the result will look something like this:

<template>
  <RSelect :items="myLongItems" groupIdentifier="title" itemsKey="cities" :itemExtractor="itemExtractor">
    <template #default="{ optimizedItems }">
      <ROption v-for="item in optimizedItems" :value="item.id" :text="item.title" />
    </template>
  </RSelect>
</template>

<script setup>
const myLongItems = ref([
  {
    title: "UK",
    cities: [
      { name: "London", id: 1 }, { name: "Bristol", id: 2 }
    ],
  },
  {
    title: "Russia",
    cities: [
      { name: "Moscow", id: 3 }, { name: "Saint Petersburg", id: 4 }, { name: "Novosibirsk", id: 5 }
    ],
  },
])

const itemExtractor = (item) => {
  return {
    ...item,
    value: item.id,
    text: item.title
  };
};
</script>
Select with 1k items 10 children each

Creating Options

You can allow user to create new option. to do so you need to add canCreateOption to RSelect and use the newOption prop which is a function that will be called whenever user has something typed on search input and pressed Enter. the type of function is

({newOption: string, isAlreadyInValue: boolean, isAlreadyInOptions: boolean}): Promise<boolean> | boolean
  • newOption is what user has type in input.
  • isAlreadyInValue looks in modelValue for the typed string and is true if there is the same item on modelValue.
  • isAlreadyInOptions looks in options state by value key of each option and is true if there is any item.

Returning true closes the dropdown and resets search (if keepOpenAfterSelection is false).

Using noDropdown prop you can hide dropdown if it's only for making new items.

in order to handle new items you check if item is not already a selected value which means isAlreadyInValue is false and push new items to modelValue ( if it's multiple selection ).

you can push the newly create item to list of your options or use setSelectedItems exposed method for updating selected values.

You need to pass either items prop or have ROption in the default slot unless noDropdown is true.
const onNewOption = ({ newOption, isAlreadyInValue, isAlreadyInOptions }) => {
  // 1. Update v-model
  if (!isAlreadyInValue) {
    selectedItems.value.push(newOption);
  }
  
  // 2. Update list of options
  // if dropdown is hidden you can skip checking if there is already same item in list.
  items.value.push({
    text: newOption,
    value: newOption,
  });

  // 2 alternative: You can also use exposed function of `setSelectedItems` if you do not care about the options. but you MUST make sure it's called after vModel is updated. for example using nextTick:
  // nextTick(() => {
  //   selectRef.value.setSelectedItems([
  //     {
  //       value: newOption,
  //       text: newOption,
  //     },
  //   ]);
  // }); 

  // Should return a boolean to specify whether it was successfull or not
  return true
};
Without dropdown and we do not care about items prop or ROption
[]
Create Items By Pressing Enter
With dropdown and we add new option to list of options
[]
Create Items By Pressing Enter
The reason creating new options is not handled in RSelect itself and leaves the calculation of adding new items to developer is because it gives more flexibility to using the custom format on your v-model or list of options.

State

Refer to Input State

Props

NameTypeRequiredDefault ValueDescription
searchablebooleanNofalseIf true, allows users to search for and select options from a dropdown menu.
multiplebooleanNofalseIf true, allows users to select multiple options from the dropdown menu.
modelValuearray | number | stringYesundefinedThe selected value(s) of the dropdown menu. If multiple is set to true, an array of values is expected.
placeholderstringNo""The text displayed inside the dropdown menu when no options are selected.
disabledbooleanNofalseIf true, disables the dropdown menu.
labelstringNoundefinedThe label displayed above the dropdown menu.
keepOpenAfterSelectionbooleanNofalseIf true, keeps the dropdown menu open after a selection has been made.
colorstringNoundefinedThe color of the Select.
errorbooleanNofalseIf true, adds error styling.
messagestringNoundefinedThe message displayed below the dropdown menu.
inputPropsobject of anyNoundefinedProps to pass down to input
noDropdownOnEmptySearchbooleanNoundefinedWhen search value is empty dropdown will not show (or hide of it is was open)
noDropdownbooleanNoundefinedwhether do show a dropdown or not. can be usefull when user can create options by itself
canCreateOptionbooleanNoundefinedif true, newOption will be visible as user starts typing on search field and newOption event will be emitted on click of new option or clicking enter
loadingbooleanNoundefinedLoading state on select ( shows a spinner instead of chevron )
renderPlaceholder(parameter: Option | Option[]) => stringNoCustom PlaceholderWhen some value is seleted this placeholder will be shown
customSearch(parameter: string) => voidNoundefinedcalled when input text changes. you can use this function to filter your items from an API or change search behaviour
itemsany[]Noundefinedif provided will Optimized Items will be used
itemsKeystringNo'items'used for when using optimized items and list is nested ( grouped ) Usage for grouped items
groupIdentifierstringNo'id'used for when using optimized items and list is nested ( grouped ) Usage for grouped items
paginationOffsetnumberNo40distance from bottom in pixels to trigger rendering new items
perPagenumberNo10number of items per page on optimized list
itemExtractor(parameter: any) => OptionNoundefinedused when format of item do not match the format of ROption props ( missing value ): Optimized Items
dropdownClassstringNoundefinedextra classes to pass down to dropdown ( since it's rendered on body you need to specify global styles for it. )
onNewOption(arg0: { newOption: string; isAlreadyInValue: boolean; isAlreadyInOptions: boolean }) => Promise<boolean> | booleanNoundefinedUsed for adding new items ( tags ). if returns true dropdown will close and search input resets. otherwise both will stay
popperOptions-Noundefinedextra options to pass to popper instance

Events

EventArgumentsDescription
open-Called when dropdown opens.
close-Called when dropdown closes.
afterTransitionEnd-Called when dropdown close transition is done.
search-Called search input value changes.

Exposed

Namevaluedescription
setSelectedItems(Option[]): voidFunction for setting selected items (usefull when items are not available but there are some values selected)
rInputInstanceType\The input of RSelect (can be usefull for calling methods of RInput).
open() => voidfunction for opening dropdown
close(resetSearch: boolean = true, blur: boolean = true) => voidfunction for closing dropdown
resetSearch() => voidfunction for clearing search input

RSelect Slots

Nameslot propsdescription
default{optimizedItems}For rendering ROption or RSelectGroup. will have optimizedItems if :items prop is available
selectedItem{ ...option, remove }For rendering custom tags on multiple selection
noItems-When there are no options
before-before slot of RInput
inputIcon-icon slot of RInput
toggleIcon{toggleOpen, active, loading}custom toggle icon
loadingSpinner{loading}custom loading spinner
newOption{addNewOption, search}will be visible if canCreateOption is true and search is not empty.

ROption Props

NameTypeRequiredDefault ValueDescription
valuestring | numberYes0Value of option.
textstringNo""Text of option.
disabledbooleannofalseWhether item is disabled or not.
colorstringnoundefinedColor of option.
contextRecord<string, any>noundefinedAny custom object to later be used.

RSelectGroup Props

NameTypeRequiredDefault ValueDescription
titlestringNoundefinedTitle of group
keepTitleOnSearchbooleanNoundefinedBy default title hides when search input is not empty, if set to true you'd better hide it's options when there are no children available

RSelectGroup Slots

Nameslot propsdescription
default-For rendering ROptions
header-Header of group. ( will replace title and ignores both title and keepTitleOnSearch props )