Single Select
Selects are interactive components that allow users to choose from a list of options.
Basic Usage
V-Model: ""
<template>
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
const selectModel = ref('');
const options = ref([
{ text: 'Apple', value: 'apple' },
{ text: 'Banana', value: 'banana' },
{ text: 'Cherry', value: 'cherry' },
{ text: 'Date', value: 'date' },
{ text: 'Elderberry', value: 'elderberry' },
{ text: 'Fig', value: 'fig' },
{ text: 'Grape', value: 'grape' },
{ text: 'Nectarine', value: 'nectarine' },
{ text: 'Orange', value: 'orange' },
{ text: 'Papaya', value: 'papaya' },
{ text: '89 Quince', value: '50' },
]);
</script>
Grouped Items By
You can group items by default
, A-Z
or Z-A
order by passing the group-items-by
prop and specifying the desired grouping type.
<template>
<div class="spr-grid spr-gap-4">
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
group-items-by="A-Z"
/>
</div>
</template>
Search
The search feature allows users to quickly filter and find specific items within the select list by typing in a search query.
- Use the
searchable-options
prop to enable the search input within the select component.
V-Model: ""
<template>
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
searchable
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
const selectModel = ref('');
const options = ref([
{ text: 'Apple', value: 'apple' },
{ text: 'Banana', value: 'banana' },
{ text: 'Cherry', value: 'cherry' },
{ text: 'Date', value: 'date' },
{ text: 'Elderberry', value: 'elderberry' },
{ text: 'Fig', value: 'fig' },
{ text: 'Grape', value: 'grape' },
{ text: 'Nectarine', value: 'nectarine' },
{ text: 'Orange', value: 'orange' },
{ text: 'Papaya', value: 'papaya' },
{ text: '89 Quince', value: '50' },
]);
</script>
You can disable local search by passing the disabled-local-search
prop. This is useful when you want to handle search via API only, and not filter the options locally.
Use @searchString
emit to get the search string when the user types in the search input. This allows you to handle the search logic externally, such as fetching options from an API based on the search query.
<div class="spr-grid spr-gap-4">
<spr-select
id="sample-selectSearchDisabledLocalSearch"
v-model="selectModel.selectSearchDisabledLocalSearch"
label="Select Label"
placeholder="Select an option"
:options="options"
searchable
disabled-local-search
/>
<code class="spr-font-medium">
V-Model: {{ selectModel.selectSearchDisabledLocalSearch ? selectModel.selectSearchDisabledLocalSearch : `""` }}
</code>
</div>
```vue
<template>
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
searchable
disabled-local-search
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
const selectModel = ref('');
const options = ref([
{ text: 'Apple', value: 'apple' },
{ text: 'Banana', value: 'banana' },
{ text: 'Cherry', value: 'cherry' },
{ text: 'Date', value: 'date' },
{ text: 'Elderberry', value: 'elderberry' },
{ text: 'Fig', value: 'fig' },
{ text: 'Grape', value: 'grape' },
{ text: 'Nectarine', value: 'nectarine' },
{ text: 'Orange', value: 'orange' },
{ text: 'Papaya', value: 'papaya' },
{ text: '89 Quince', value: '50' },
]);
</script>
Pre-Selected Items
Pre-selected items are options that are automatically selected when the select is first displayed. The v-model
for the select component supports:
- String: For single selection by value (e.g.,
'apple'
). - Number: For single selection by number value (e.g.,
42
). - Array of strings or numbers: For single selection by array (e.g.,
['apple']
or[42]
). - Object: For single selection by object reference (e.g.,
{ text: 'Apple', value: 'apple' }
). See more in the Supported Value Types.
V-Model: apple
<template>
<div class="spr-grid spr-gap-4">
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
group-items-by="A-Z"
/>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
const selectModel = ref(['apple']);
</script>
You can also pre-select items with search functionality. This allows users to see the pre-selected items while still being able to search through the options.
Placements
Placement refers to where the select popper will be positioned relative to its trigger element (e.g., button, input field). Pass the placement
props to modify the placement of the select popper.
The available placement options are: auto
, auto-start
, auto-end
, top
, top-start
, top-end
, right
, right-start
, right-end
, bottom
, bottom-start
, bottom-end
, left
, left-start
, and left-end
.
The default placement is bottom
.
Clearable
The clearable feature allows users to easily remove the selected value from the select input. This is particularly useful for forms where users may want to reset their selection without having to open the select.
V-Model: ""
Width and Popper Width
You can modify the width of the select component in two ways: by adjusting the width of the select wrapper or by changing the width of the select popper.
Width
- Is the overall width wrapper of both parent element and popper element.
Popper Width
- Width of only popper element
<template>
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
width="50%"
popper-width="200px"
/>
</template>
Popper Strategy
The Popper strategy is primarily used when working with elements like modal. It helps control the positioning behavior of popper. The strategy ensures that the popper element is dynamically positioned based on the viewport, the reference element, or other factors such as scrolling or resizing.
By default, the Popper strategy is set to absolute
, which positions the popper element relative to the nearest positioned ancestor (usually the body element). However, you can change the strategy
to fixed
, which positions the popper element relative to the viewport, ensuring that it remains in place even when the page is scrolled.
Pass the prop popper-strategy
to change the behavior position of the popper.
Important to note:
Do not forget to pass prop wrapperPosition
to overwrite relative
position into initial
.
<template>
<spr-button tone="success" @click="modalModel = true">Open Modal</spr-button>
<spr-modal v-model="modalModel" title="Select with Modal">
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
wrapper-position="initial"
popper-strategy="fixed"
/>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
</spr-modal>
</template>
Infinite Scroll
Infinite scroll allows the select list to load more items as the user scrolls. This feature is particularly useful for back-end API integration. Instead of loading the entire list at once, new items are dynamically added as needed, improving performance and usability. Pass @infinite-scroll-trigger
emit to get the trigger of options when it reaches bottom.
When working with infinite scroll and API-driven selects, you can use the display-text
prop to show a display value in the input on initial load (for example, when you only have the selected value and not the full option object yet). This is especially helpful for large datasets where you don't want to fetch all options at once.
Paginated Options - Should load 10 Items per page:
Pagination:
{ "totalpages": 10, "currentPage": 1 }
Data:
[]<template>
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="optionsAPI"
:display-text="displayText"
@infinite-scroll-trigger="handleInfiniteScrollTrigger"
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
const selectModel = ref(51); // Initial value for the select
const displayText = ref('Border Terrier'); // Display text for the selected option
const optionsAPI = ref<optionsType[]>([]);
const APIisLoading = ref(false);
const pagination = ref({
totalpages: 10,
currentPage: 1,
});
const setOptionsViaAPI = () => {
getNextOptionsViaAPI();
};
const handleInfiniteScrollTrigger = () => {
if (pagination.value.currentPage === pagination.value.totalpages || APIisLoading.value) return;
APIisLoading.value = true;
pagination.value.currentPage += 1;
getNextOptionsViaAPI();
};
const getNextOptionsViaAPI = async () => {
try {
const response = await fetch(`https://api.thedogapi.com/v1/breeds?page=${pagination.value.currentPage}&limit=10`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const options = await response.json();
optionsAPI.value = options.length
? [
...(optionsAPI.value || []),
...options.map((option) => ({
text: option.name,
value: option.id,
})),
]
: [];
APIisLoading.value = false;
} catch (error) {
console.error('There was a problem with the fetch operation:', error);
}
};
</script>
Active, Disabled, Error States
For guidance on implementing error, active, and disabled states in the select component, you can refer to the documentation for the input text component, as the approach is similar. See the Input Form for detailed instructions.
Active State
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
active
/>
Disabled State
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
disabled
/>
Error State
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
error
/>
Helper Message
A helper message is a text label below the input field that provides additional information about instructions, formatting hints, validation feedback, etc.
To display the helper message, set the display-helper
prop to true
and add the helper-text
prop with the helper message text. You can also insert an icon with the helper-icon
prop. This uses the Iconify icon library.
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
helper-text="This is a helper message"
display-helper
/>
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
helper-text="This is an error message"
helper-icon="ph:warning-circle-fill"
display-helper
error
/>
Alternatively, you can use the helperMessage
slot to display a custom helper message.
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
display-helper
>
<template #helperMessage>This is a helper message</template>
</spr-select>
<spr-select
id="sample-select"
v-model="selectModel"
label="Select Label"
placeholder="Select an option"
:options="options"
display-helper
error
>
<template #helperMessage>
<icon icon="ph:warning-circle-fill" width="20px" height="20px" />
<span>This is an error message</span>
</template>
</spr-select>
Supported Value Types
The select component supports various types of values. The v-model
binding can accept different data formats depending on your needs.
Single Primitive Values
For single selection of primitive types like strings or numbers:
Value: apple
Value: 42
<template>
<spr-select
id="string-select"
v-model="stringValue"
label="Select Label"
placeholder="Select an option"
:options="stringoptions"
/>
<spr-select
id="number-select"
v-model="numberValue"
label="Select Label"
placeholder="Select an option"
:options="numberoptions"
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
// For string values
const stringValue = ref('apple'); // Single string value
// For number values
const numberValue = ref(42); // Single number value
const stringoptions = ref([
{ text: 'Apple', value: 'apple' },
{ text: 'Banana', value: 'banana' },
{ text: 'Cherry', value: 'cherry' },
]);
const numberoptions = ref([
{ text: '42', value: 42 },
{ text: '100', value: 100 },
{ text: '200', value: 200 },
]);
</script>
Single Object Values
For single selection of full objects:
Value: { "id": 1, "name": "John", "role": "Developer" }
<template>
<spr-select
id="object-select"
v-model="selectedUser"
label="Select Label"
placeholder="Select an option"
:options="userList"
text-field="name" // Specify which field to display as text
value-field="id" // Specify which field to use as value
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
// Object selection using full object reference
const selectedUser = ref({ id: 1, name: 'John', role: 'Developer' });
const userList = ref([
{ id: 1, name: 'John', role: 'Developer' },
{ id: 2, name: 'Jane', role: 'Designer' },
{ id: 3, name: 'Bob', role: 'Manager' }
]);
</script>
API Reference
Name | Description | Type | Default |
---|---|---|---|
id | Required to bind popper within the select | String | - |
v-model | Value binding for the select. Accepts:
| String | Number | Object | Array | [] |
options | List of options composed of text and value properties, or array of strings/objects | optionsType[] | string[] | object[] | [] |
group-items-by | Group items by order: 'A-Z', 'Z-A' | 'A-Z' | 'Z-A' | - |
text-field | Field name to use for display text when using dynamic object arrays | String | 'text' |
value-field | Field name to use for value when using dynamic object arrays | String | 'value' |
display-text | Display text to show in the input on initial load (useful for API-driven selects). This value is only shown once, and will be replaced when the user selects a new item. | String | - |
placeholder | Placeholder text for the input | String | - |
label | Label text for the input | String | '' |
placement | Placement of the select popper (e.g., 'bottom', 'top', 'left', 'right') | String | 'bottom' |
searchable | Searchable is to allow typing in the input. If searchable is not set or is false, the input will be readonly and users cannot type. | Boolean | false |
disabled-local-search | Disables local search when the searchable prop is set to true. This is useful when you want to handle search via API only. | Boolean | false |
popper-strategy | Defines how the select's popper is positioned: 'absolute' or 'fixed' | String | 'absolute' |
popper-width | Width of the select's popper | String | '100%' |
width | Width of the select component wrapper | String | '100%' |
wrapper-position | CSS position of the select wrapper | String | 'relative' |
disabled | Disables the select if true | Boolean | false |
clearable | Allows the user to clear the selected value with a clear button | Boolean | false |
Events
Event | Description | Payload |
---|---|---|
@update:model-value | Event emitted when the model value changes | Any |
@infinite-scroll-trigger | Event emitted when the select is scrolled to the bottom (for dynamic data loading) | None |
@searchString | Event emitted when you type in the search input | None |