Select
KSelect is custom component alternative for native <select>
element.
<KSelect :items="selectItems" />
Props
v-model
Use v-model
for two-way value binding.
Selected service: {{ selectValue || 'none' }}
<KSelect
v-model="selectValue"
:items="selectItems"
/>
items
Prop for providing select item options. Supports grouping items under one group name through providing optional group
property.
interface SelectItem {
label: string
value: string | number
key?: string // optional parameter that will be appended with `-selected` when selected
selected?: boolean
disabled?: boolean
group?: string
}
<KSelect :items="[{
label: 'Service A',
value: 'a',
selected: true,
}, {
label: 'Service B',
value: 'b',
}, {
label: 'Service F',
value: 'f',
disabled: true,
}, {
label: 'Service A1',
value: 'a1',
group: 'Series 1',
}, {
label: 'Service B1',
value: 'b1',
group: 'Series 1',
}, {
label: 'Service A2',
value: 'a2',
group: 'Series 2',
}, {
label: 'Service B2',
value: 'b2',
group: 'Series 2',
}]" />
label
Label associated with the input element.
<KSelect label="Label" :items="selectItems" />
labelAttributes
Label attributes to be passed to underlying KLabel component.
<KSelect :label-attributes="{ info: 'I use the KLabel `info` prop' }" label="Label" :items="selectItems" />
placeholder
Placeholder to be displayed when no item is selected.
<KSelect placeholder="Select service" :items="selectItems" />
clearable
When set to true
, the clear icon will be displayed in front of selected item.
<KSelect clearable :items="selectItems" />
help
Help text to be displayed below the select element.
<KSelect help="Helpful text." :items="selectItems" />
error
When set to true
, error styling will apply.
<KSelect error help="You can use `help` prop for displaying error messages." :items="selectItems" />
width
Use this prop to limit element's width.
<KSelect width="200" :items="selectItems" />
dropdownMaxHeight
Maximum height for dropdown container. Defaults to 300px
.
<KSelect dropdown-max-height="300" :items="selectItems" />
dropdownFooterText
Text to be displayed at the bottom of the dropdown container. Can also be slotted.
<KSelect dropdown-footer-text="Helpful text in the dropdown." :items="selectItems" />
dropdownFooterTextPosition
Defaults to sticky
, but also accepts static
value should you want text passed through dropdownFooterText
prop to be displayed at the bottom of dropdown container after all items.
<KSelect dropdown-footer-text-position="static" dropdown-footer-text="Helpful text in the dropdown." :items="selectItems" />
enableFiltering
By default, items passed to KSelect are not searchable. When enableFiltering
prop is true, clicking on the select element will turn it into input field. You may filter items by typing in the input which will hide non-matching items.
<KSelect enable-filtering placeholder="Try searching for 'service a'" :items="selectItems" />
filterFunction
A custom function to perform item filtering. Expects an object with query string and items to filter through. To keep track of user input you can listen to @query-change
event.
interface SelectFilterFunctionParams {
query: string
items: SelectItem[]
}
TIP
When using filterFunction
prop in conjunction with enableItemCreation
set to true
you must keep track of added and removed custom items to be able to provide the most up to date items to filterFunction
. To achieve that you want to utilize @item-added
and @item-removed
events.
<template>
<KSelect enable-filtering :filter-function="envFilter" placeholder="Try searching for 'dev' or 'prod'" :items="selectItems">
<template #item-template="{ item }">
{{ item?.label }}
<KBadge v-if="item.env">{{ item.env }}</KBadge>
</template>
</KSelect>
</template>
<script setup lang="ts">
import type { SelectItem, SelectFilterFunctionParams } from '@kong/kongponents'
const selectItems: SelectItem[] = [{
label: 'Service A',
value: 'a',
}, {
label: 'Service B',
value: 'b',
env: 'dev',
}, {
label: 'Service F',
value: 'f',
disabled: true,
}, {
label: 'Service A1',
value: 'a1',
group: 'Series 1',
}, {
label: 'Service B1',
value: 'b1',
group: 'Series 1',
}, {
label: 'Service A2',
value: 'a2',
group: 'Series 2',
env: 'prod',
}, {
label: 'Service B2',
value: 'b2',
group: 'Series 2',
env: 'prod',
}]
const envFilter = (params: SelectFilterFunctionParams) =>
params?.items?.filter((item: SelectItem) =>
item.label?.toLowerCase().includes(params.query?.toLowerCase())
|| item.env?.includes(params.query?.toLowerCase()))
</script>
TIP
Should you need to disable the default filter function while still allowing filtering (for example when you want to handle filtering asynchronously by querying an API), you can provide a function that always returns boolean true
to this prop, like so:
<KSelect
enable-filtering
:filter-function="() => true"
:items="selectItems"
/>
reuseItemTemplate
Reuse the same display format provided via the item-template
slot for the selected item.
<KSelect
:items="selectItems"
reuse-item-template
>
<template #item-template="{ item }">
<KongIcon />
{{ item?.label }}
</template>
</KSelect>
enableItemCreation
KSelect can offer users the ability to add custom items to the list by typing the item they want to and then clicking the ... (Add new value)
item at the bottom of the list, which will also automatically select it.
Newly created items will have a label
consisting of the user input and a randomly generated id for the value
to ensure uniqueness. The item will also have an attribute custom
set to true
. This action triggers an item-added
event containing the added item data.
Deselecting the item will completely remove it from the list and underlying data, and trigger a item-removed
event containing the removed item's data.
NOTE
You cannot add an item if the label
matches the label
of a pre-existing item. In that scenario the ... (Add new value)
item will not be displayed.
<KSelect enable-item-creation enable-filtering placeholder="Try searching for 'service d'" :items="selectItems" />
itemCreationValidator
Prop for passing a function for input validation when item creation is enabled.
The function takes the query input string as a single parameter and must return a boolean
value.
When the function passed through itemCreationValidator
returns false
, the "Add new value" button will be disabled.
<template>
<KSelect
enable-filtering
enable-item-creation
:item-creation-validator="itemCreationValidator"
:items="selectItems"
@query-change="onQueryChange"
>
<template
v-if="showNewItemValidationError"
#dropdown-footer-text
>
<span class="item-creation-validation-error-message">
New item should be at least 3 characters long.
</span>
</template>
</KSelect>
</template>
<script setup lang="ts">
import type { SelectItem } from '@kong/kongponents'
const selectItems: SelectItem[] = [...]
const showNewItemValidationError = ref<boolean>(false)
const itemCreationValidator = (value: string) => value.length >= 3
const onQueryChange = (query: string): void => {
showNewItemValidationError.value = query ? !itemCreationValidator(query) : false
}
</script>
<style lang="scss" scoped>
.item-creation-validation-error-message {
color: $kui-color-text-danger;
}
</style>
loading
Pass true
to display loader instead of items in the dropdown. KSelect's item
prop is reactive to changes by design, so that should you need to perform async item fetching/filtering you can execute that logic within the host app and pass items back to KSelect.
The example below utilizes the @query-change
event to simulate async item fetching behind the scenes.
<template>
<KSelect
v-model="asyncItemsModel"
enable-filtering
:items="asyncItems"
:loading="asyncItemsLoading"
@query-change="onAsyncQueryChange"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { SelectItem } from '@kong/kongponents'
const asyncItems: SelectItem[] = [{
label: 'Service A',
value: 'a',
}, {
label: 'Service B',
value: 'b',
}, {
label: 'Service F',
value: 'f',
disabled: true,
}, ...]
const asyncItemsInitial: SelectItem[] = JSON.parse(JSON.stringify(asyncItems.value))
const asyncItemsModel = ref<string>('')
const asyncItemsQuery = ref<string>('')
const asyncItemsLoading = ref<boolean>(false)
const onAsyncQueryChange = (query: string): void => {
if (asyncItemsQuery.value !== query) {
asyncItemsQuery.value = query
fetchAsyncItems()
}
}
const fetchAsyncItems = (): void => {
asyncItemsLoading.value = true
setTimeout(() => {
// normally we would perform api fetching here
// but for the sake of this example let's just filter items locally with some timeout
const items = JSON.parse(JSON.stringify(asyncItemsInitial))
asyncItems.value = items.filter((item: SelectItem) => item.label?.toLowerCase().includes(asyncItemsQuery.value?.toLowerCase()))
asyncItemsLoading.value = false
}, 2000)
}
</script>
kpopAttributes
Attributes to be passed to underlying KPopover component. See KPopover's props for more info.
HTML Attributes
required
KSelect will display a red dot next to label when required
attribute is passed.
<KSelect
label="Label"
required
:items="selectItems"
/>
disabled
Use this attribute to disable interaction with the element.
<KSelect
label="Disabled"
disabled
:items="selectItems"
/>
Slots
item-template
Use this slot to pass custom content to the items. The slot exposes item
slot prop.
<template>
<KSelect :items="selectItems">
<template #item-template="{ item }">
<div class="custom-item">
<KongIcon />
<div class="custom-item-title-container">
<span class="custom-item-title">{{ item?.label }}</span>
<span class="custom-item-description">{{ item?.label }} description.</span>
</div>
</div>
</template>
</KSelect>
</template>
<style lang="scss" scoped>
.custom-item {
display: flex;
flex-direction: row;
gap: $kui-space-30;
&-title-container {
flex: 1;
}
&-title {
display: block;
}
&-description {
color: $kui-color-text-neutral;
display: block;
font-size: $kui-font-size-20;
}
}
</style>
selected-item-template
Use this slot to provide custom content to the selected item. The slot exposes item
slot prop.
<KSelect :items="selectItems">
<template #selected-item-template="{ item }">
<KongIcon />
{{ item?.label }}
</template>
</KSelect>
dropdown-footer-text
A slot alternative for dropdownFooterText
prop.
<KSelect :items="selectItems">
<template #dropdown-footer-text>
<KongIcon />
Dropdown footer content.
</template>
</KSelect>
loading
Content to be displayed when loading
prop is true
. Note that this slot only applies when enableFiltering
is true
.
<KSelect :loading="loading" enable-filtering :items="selectItems">
<template #loading>
Services loading...
</template>
</KSelect>
empty
Slot to display custom content when items is empty or no items match filter query.
<KSelect :items="[]">
<template #empty>
No services found.
</template>
</KSelect>
label-tooltip
Use this slot to pass any custom content to label tooltip.
<KSelect label="Label" :items="selectItems">
<template #label-tooltip>Id: <code>8576925e-d7e0-4ecd-8f14-15db1765e69a</code></template>
</KSelect>
before
Use this slot for inserting icons before the input field.
Events
selected
Event payload is select item.
input and update:modelValue
Event payload is selected item value
.
change
Event payload is select item.
query-change
Event payload is query string.
item-added
Event payload is added item.
item-removed
Event payload is removed item.