Skip to content

Single Select

Selects are interactive components that allow users to choose from a list of options.

Basic Usage

V-Model: ""
vue
<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.

vue
<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>

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: ""
vue
<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.

vue
<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
vue
<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

vue
<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.

vue
<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:

[]
vue
<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

vue
<spr-select
  id="sample-select"
  v-model="selectModel"
  label="Select Label"
  placeholder="Select an option"
  :options="options"
  active
/>

Disabled State

vue
<spr-select
  id="sample-select"
  v-model="selectModel"
  label="Select Label"
  placeholder="Select an option"
  :options="options"
  disabled
/>

Error State

vue
<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.

This is a helper message
This is an error message
vue
<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.

This is a helper message
This is an error message
vue
<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

vue
<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" }

vue
<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

NameDescriptionTypeDefault
idRequired to bind popper within the selectString-
v-modelValue binding for the select. Accepts:
  • Single primitive values: String ('apple'), Number (42)
  • Single object values: Full objects ({ id: 1, name: 'John' })
  • Array of values: Array of strings, numbers, or objects
The returned value type will match the input type (preserving strings, numbers, and objects).
String | Number | Object | Array[]
optionsList of options composed of text and value properties, or array of strings/objectsoptionsType[] | string[] | object[][]
group-items-byGroup items by order: 'A-Z', 'Z-A''A-Z' | 'Z-A'-
text-fieldField name to use for display text when using dynamic object arraysString'text'
value-fieldField name to use for value when using dynamic object arraysString'value'
display-textDisplay 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-
placeholderPlaceholder text for the inputString-
labelLabel text for the inputString''
placementPlacement 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. Booleanfalse
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. Booleanfalse
popper-strategyDefines how the select's popper is positioned: 'absolute' or 'fixed'String'absolute'
popper-widthWidth of the select's popperString'100%'
widthWidth of the select component wrapperString'100%'
wrapper-positionCSS position of the select wrapperString'relative'
disabledDisables the select if trueBooleanfalse
clearableAllows the user to clear the selected value with a clear buttonBooleanfalse

Events

EventDescriptionPayload
@update:model-valueEvent emitted when the model value changesAny
@infinite-scroll-triggerEvent emitted when the select is scrolled to the bottom (for dynamic data loading)None
@searchStringEvent emitted when you type in the search inputNone

Product Uses

Sprout HR
Sprout Sidekick