Select
Select component for choosing single or multiple options
Default Select
<template>
<HLSelect :options="simpleSelectOptions" :value="selectedValue" @update:value="handleSimpleChange" />
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const simpleSelectOptions = [
{
label: 'Option 1',
value: 'option1',
},
{
label: 'Option 2',
value: 'option2',
},
{
label: 'Option 3',
value: 'option3',
},
]
const handleSimpleChange = value => {
selectedValue.value = value
}
</script>With Icon
<template>
<HLSelect type="avatar" :options="options" :value="selectedValue" @update:value="handleChange">
<template #icon>
<div class="hr-select-menu-placeholder-icon">
<User01Icon />
</div>
</template>
</HLSelect>
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { User01Icon } from '@gohighlevel/ghl-icons/24/outline'
import { ref } from 'vue'
const selectedValue = ref('')
const handleChange = value => {
selectedValue.value = value
}
</script>const options = [
{
type: 'group',
label: 'Rubber Soul',
key: 'Rubber Soul',
children: [
{
label: 'Drive My Car',
value: 'song1',
description: 'Drive My Car.ogg',
tagColor: 'blue',
},
{
label: 'Norwegian Wood',
value: 'song2',
description: 'Norwegian Wood.ogg',
tagColor: 'green',
},
{
label: "Everybody's Got Something to Hide Except Me and My Monkey",
value: 'song0',
description:
'lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.',
tagColor: 'blue',
},
// ... other songs
],
},
{
type: 'group',
label: 'Let It Be',
key: 'Let It Be Album',
children: [
{
label: 'Two Of Us',
value: 'Two Of Us',
tagColor: 'purple',
},
{
label: 'Dig A Pony',
value: 'Dig A Pony',
description: 'Dig A Pony.avi',
tagColor: 'orange',
},
// ... other songs
],
},
]Searchable Select
<template>
<HLSelect filterable showSearchIcon :options="options" :value="selectedValue" @update:value="handleChange" />
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const selectedValue = ref('')
const handleChange = value => {
selectedValue.value = value
}
</script>const options = [
{
type: 'group',
label: 'Rubber Soul',
key: 'Rubber Soul',
children: [
{
label: 'Drive My Car',
value: 'song1',
description: 'Drive My Car.ogg',
tagColor: 'blue',
},
{
label: 'Norwegian Wood',
value: 'song2',
description: 'Norwegian Wood.ogg',
tagColor: 'green',
},
{
label: "Everybody's Got Something to Hide Except Me and My Monkey",
value: 'song0',
description:
'lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.',
tagColor: 'blue',
},
// ... other songs
],
},
{
type: 'group',
label: 'Let It Be',
key: 'Let It Be Album',
children: [
{
label: 'Two Of Us',
value: 'Two Of Us',
tagColor: 'purple',
},
{
label: 'Dig A Pony',
value: 'Dig A Pony',
description: 'Dig A Pony.avi',
tagColor: 'orange',
},
// ... other songs
],
},
]Clearing the value
When you want to clear the value of the select, you can set the value to null. Setting the value to undefined will create inconsistent behavior.
<template>
<HLSelect :options="options" v-model:value="selectedValue2" />
<HLButton @click="selectedValue2 = null">Clear Value</HLButton>
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const selectedValue2 = ref('')
const options = ref([
{ label: 'Option 1', value: 'option1' },
{ label: 'Option 2', value: 'option2' },
{ label: 'Option 3', value: 'option3' },
])
</script>Multiple Selection
<template>
<HLSelect
multiple
type="avatar"
filterable
showSearchIcon
:options="options"
:value="selectedValue"
:showAvatarInTags="false"
@update:value="handleChange"
id="select-multiple"
/>
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const selectedValue = ref('')
const handleChange = value => {
selectedValue.value = value
}
</script>const options = [
{
type: 'group',
label: 'Rubber Soul',
key: 'Rubber Soul',
children: [
{
label: 'Drive My Car',
value: 'song1',
description: 'Drive My Car.ogg',
tagColor: 'blue',
},
{
label: 'Norwegian Wood',
value: 'song2',
description: 'Norwegian Wood.ogg',
tagColor: 'green',
},
{
label: "Everybody's Got Something to Hide Except Me and My Monkey",
value: 'song0',
description:
'lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.',
tagColor: 'blue',
},
// ... other songs
],
},
{
type: 'group',
label: 'Let It Be',
key: 'Let It Be Album',
children: [
{
label: 'Two Of Us',
value: 'Two Of Us',
tagColor: 'purple',
},
{
label: 'Dig A Pony',
value: 'Dig A Pony',
description: 'Dig A Pony.avi',
tagColor: 'orange',
},
// ... other songs
],
},
]Multiple Selection without Avatar
<template>
<HLSelect
multiple
filterable
showSearchIcon
:options="simpleMultiSelectOptions"
:value="selectedValue"
@update:value="handleSimpleMultiChange"
id="select-multiple"
:showAvatarInTags="false"
/>
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const selectedValue = ref('')
const handleSimpleMultiChange = value => {
selectedValue.value = value
}
</script>const simpleMultiSelectOptions = [
{
label: 'Option 1 with a long label to test the overflow',
value: 'option1',
},
{
label: 'Option 2 with a long label to test the overflow',
value: 'option2',
},
{
label: 'Option 3 with a long label to test the overflow',
value: 'option3',
},
{
label: 'Option 4',
value: 'option4',
},
{
label: 'Option 5',
value: 'option5',
},
{
label: 'Option 6',
value: 'option6',
},
]Tag Truncation
When using multiple selection with long tag labels, you can enable tag truncation to prevent tags from overflowing their container. This is particularly useful when dealing with lengthy option labels.
<template>
<HLSelect
multiple
filterable
showSearchIcon
:allowTagTruncation="true"
:maxTagWidth="120"
:options="options"
:value="selectedValue"
@update:value="handleChange"
id="select-truncated"
:showAvatarInTags="false"
/>
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const selectedValue = ref('')
const handleChange = value => {
selectedValue.value = value
}
</script>const options = [
{
label: 'Option 1 with a very long label that would normally overflow',
value: 'option1',
},
{
label: 'Option 2 with another extremely long label for testing truncation',
value: 'option2',
},
{
label: 'Option 3 with yet another long label to demonstrate truncation behavior',
value: 'option3',
},
{
label: 'Short option',
value: 'option4',
},
]Remote Search
Use remote search when you need to fetch options dynamically from an API or when dealing with large datasets that should be filtered server-side.
<template>
<HLSelect
id="remote-search"
:value="selectedValue"
:options="filteredOptions"
:loading="loading"
:filterable="true"
:remote="true"
placeholder="Type to search..."
aria-label="Remote search select example"
@search="handleSearch"
@update:value="handleChange"
/>
</template>
<script setup>
import { ref } from 'vue'
import { HLSelect } from '@platform-ui/highrise'
const selectedValue = ref(null)
const loading = ref(false)
const filteredOptions = ref([])
const handleSearch = async query => {
loading.value = true
try {
// Simulate API delay
await new Promise(resolve => setTimeout(resolve, 1000))
// Filter results if there's a query, otherwise show all
filteredOptions.value =
query && query.trim()
? InfiniteScrollOptions.value.filter(option => option.label.toLowerCase().includes(query.toLowerCase().trim()))
: InfiniteScrollOptions.value
} catch (error) {
console.error('Search failed:', error)
filteredOptions.value = []
} finally {
loading.value = false
}
}
// Load initial options
handleSearch('')
const handleChange = (value, option) => {
selectedValue.value = value
console.log('Selected:', { value, option })
}
</script>Infinite Scroll
<template>
<HLSelect
:options="InfiniteScrollOptions"
:value="infiniteSelectedValue"
@update:value="handleInfiniteChange"
@scroll="handleScroll"
:reset-menu-on-options-change="false"
:loading="infiniteLoading"
/>
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const infiniteSelectedValue = ref(null)
const infiniteLoading = ref(false)
const infiniteSelectedValue = ref(null)
const handleInfiniteChange = value => {
infiniteSelectedValue.value = value
}
const handleScroll = async event => {
const scrollPosition = event.target.scrollTop + event.target.clientHeight
if (scrollPosition >= event.target.scrollHeight - 10) {
infiniteLoading.value = true
const result = await fetchOptions() // fetch API
InfiniteScrollOptions.value = [...InfiniteScrollOptions.value, ...result]
infiniteLoading.value = false
}
}
const InfiniteScrollOptions = ref([
{
label: 'Option 1',
value: 'option1',
},
{
label: 'Option 2',
value: 'option2',
},
])
</script>Inline Select Variants
Default Inline
<template>
<HLSelect :options="options" :value="selectedValue" @update:value="handleChange" :inline="true" size="sm" />
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const selectedValue = ref('')
const handleChange = value => {
selectedValue.value = value
}
</script>const options = [
{
type: 'group',
label: 'Rubber Soul',
key: 'Rubber Soul',
children: [
{
label: 'Drive My Car',
value: 'song1',
description: 'Drive My Car.ogg',
tagColor: 'blue',
},
{
label: 'Norwegian Wood',
value: 'song2',
description: 'Norwegian Wood.ogg',
tagColor: 'green',
},
{
label: "Everybody's Got Something to Hide Except Me and My Monkey",
value: 'song0',
description:
'lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.',
tagColor: 'blue',
},
// ... other songs
],
},
{
type: 'group',
label: 'Let It Be',
key: 'Let It Be Album',
children: [
{
label: 'Two Of Us',
value: 'Two Of Us',
tagColor: 'purple',
},
{
label: 'Dig A Pony',
value: 'Dig A Pony',
description: 'Dig A Pony.avi',
tagColor: 'orange',
},
// ... other songs
],
},
]Inline with CTA
<HLSelect
:options="options"
:value="selectedValue"
@update:value="handleChange"
:inline="true"
:showInlineCTA="showInlineCTA"
:show="show"
:filterable="true"
size="sm"
@handleConfirm="handleConfirm"
@handleCancel="handleCancel"
@update:show="handleUpdateShow"
/>const show = ref(false)
const showInlineCTA = ref(false)
const handleConfirm = () => {
show.value = false
showInlineCTA.value = false // Hide CTA only on confirm
}
const handleCancel = () => {
selectedValue.value = null
show.value = false
showInlineCTA.value = false // Hide CTA only on cancel
}
const handleUpdateShow = value => {
show.value = value
showInlineCTA.value = true
}Inline with Bottom Border
<template>
<HLSelect
:options="options"
:value="selectedValue"
@update:value="handleChange"
:inline="true"
:showInlineBottomBorder="true"
size="sm"
/>
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const selectedValue = ref('')
const handleChange = value => {
selectedValue.value = value
}
</script>const options = [
{
type: 'group',
label: 'Rubber Soul',
key: 'Rubber Soul',
children: [
{
label: 'Drive My Car',
value: 'song1',
description: 'Drive My Car.ogg',
tagColor: 'blue',
},
{
label: 'Norwegian Wood',
value: 'song2',
description: 'Norwegian Wood.ogg',
tagColor: 'green',
},
{
label: "Everybody's Got Something to Hide Except Me and My Monkey",
value: 'song0',
description:
'lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.',
tagColor: 'blue',
},
// ... other songs
],
},
{
type: 'group',
label: 'Let It Be',
key: 'Let It Be Album',
children: [
{
label: 'Two Of Us',
value: 'Two Of Us',
tagColor: 'purple',
},
{
label: 'Dig A Pony',
value: 'Dig A Pony',
description: 'Dig A Pony.avi',
tagColor: 'orange',
},
// ... other songs
],
},
]Inline with edit actions
<HLSelect
:options="options"
:value="selectedValue"
@update:value="handleChange"
:inline="true"
:showInlineCTA="showInlineCTA"
:showSavedMark="showSavedMark"
@handleConfirm="handleConfirm"
@handleCancel="handleCancel"
@update:show="handleUpdateShow"
size="sm"
id="select-inline-edit-actions"
>
<template #edit-actions>
<HLIcon size="16" color="var(--success-600)"><PhoneIcon /></HLIcon>
<HLIcon size="16"><Mail01Icon /></HLIcon>
</template>
</HLSelect>import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const showInlineCTA = ref(false)
const showSavedMark = ref(false)
const selectedValue = ref('')
const handleChange = value => {
selectedValue.value = value
}
const handleConfirm = () => {
showInlineCTA.value = false
showSavedMark.value = true
setTimeout(() => {
showSavedMark.value = false
}, 2500)
}
const handleCancel = () => {
selectedValue.value = null
showInlineCTA.value = false
showSavedMark.value = false
}
const handleUpdateShow = value => {
showInlineCTA.value = value
if (value) {
showInlineCTAEditActions.value = true
}
}const options = [
{
type: 'group',
label: 'Rubber Soul',
key: 'Rubber Soul',
children: [
{
label: 'Drive My Car',
value: 'song1',
description: 'Drive My Car.ogg',
tagColor: 'blue',
},
{
label: 'Norwegian Wood',
value: 'song2',
description: 'Norwegian Wood.ogg',
tagColor: 'green',
},
{
label: "Everybody's Got Something to Hide Except Me and My Monkey",
value: 'song0',
description: 'lorsum ipsum dolor...',
tagColor: 'blue',
},
// ... other songs
],
},
{
type: 'group',
label: 'Let It Be',
key: 'Let It Be Album',
children: [
{
label: 'Two Of Us',
value: 'Two Of Us',
tagColor: 'purple',
},
{
label: 'Dig A Pony',
value: 'Dig A Pony',
description: 'Dig A Pony.avi',
tagColor: 'orange',
},
// ... other songs
],
},
]Rounded Tags
<template>
<HLSelect
:options="options"
:value="selectedValue"
@update:value="handleChange"
:inline="true"
:multiple="true"
type="avatar"
:filterable="true"
:showSearchIcon="true"
:roundedTags="true"
size="sm"
/>
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const selectedValue = ref('')
const handleChange = value => {
selectedValue.value = value
}
</script>const options = [
{
type: 'group',
label: 'Rubber Soul',
key: 'Rubber Soul',
children: [
{
label: 'Drive My Car',
value: 'song1',
description: 'Drive My Car.ogg',
tagColor: 'blue',
},
{
label: 'Norwegian Wood',
value: 'song2',
description: 'Norwegian Wood.ogg',
tagColor: 'green',
},
{
label: "Everybody's Got Something to Hide Except Me and My Monkey",
value: 'song0',
description:
'lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.',
tagColor: 'blue',
},
// ... other songs
],
},
{
type: 'group',
label: 'Let It Be',
key: 'Let It Be Album',
children: [
{
label: 'Two Of Us',
value: 'Two Of Us',
tagColor: 'purple',
},
{
label: 'Dig A Pony',
value: 'Dig A Pony',
description: 'Dig A Pony.avi',
tagColor: 'orange',
},
// ... other songs
],
},
]Disabled Inline Select
<template>
<HLSelect :options="options" :value="selectedValue" @update:value="handleChange" :inline="true" :disabled="true" size="sm" />
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const selectedValue = ref('')
const handleChange = value => {
selectedValue.value = value
}
const options = [
{
label: 'Option 1',
value: 'option1',
},
]
</script>Error State
This field is required
<template>
<HLFormItem validation-status="error" feedback="This field is required">
<HLSelect
:options="options"
:value="selectedValue"
@update:value="handleChange"
:inline="true"
:showInlineCTA="showInlineCTA"
:show="show"
:filterable="true"
size="sm"
@handleConfirm="handleConfirm"
@handleCancel="handleCancel"
@update:show="handleUpdateShow"
/>
</HLFormItem>
</template>
<script setup>
import { HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const selectedValue = ref('')
const handleChange = value => {
selectedValue.value = value
}
</script>const options = [
{
type: 'group',
label: 'Rubber Soul',
key: 'Rubber Soul',
children: [
{
label: 'Drive My Car',
value: 'song1',
description: 'Drive My Car.ogg',
tagColor: 'blue',
},
{
label: 'Norwegian Wood',
value: 'song2',
description: 'Norwegian Wood.ogg',
tagColor: 'green',
},
{
label: "Everybody's Got Something to Hide Except Me and My Monkey",
value: 'song0',
description:
'lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.lorsum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam. Loresum ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec purus feugiat, molestie ipsum et, consequat nunc. Nulla facilisi. Nullam.',
tagColor: 'blue',
},
// ... other songs
],
},
{
type: 'group',
label: 'Let It Be',
key: 'Let It Be Album',
children: [
{
label: 'Two Of Us',
value: 'Two Of Us',
tagColor: 'purple',
},
{
label: 'Dig A Pony',
value: 'Dig A Pony',
description: 'Dig A Pony.avi',
tagColor: 'orange',
},
// ... other songs
],
},
]Advanced Tag Configuration with tagProps
The new tagProps object provides complete control over tag rendering in multiple selection mode.
Basic Usage
<template>
<HLSelect multiple :options="options" :value="selectedValue" @update:value="handleChange" />
</template>
<script setup>
import { ref } from 'vue'
import { HLSelect } from '@platform-ui/highrise'
const selectedValue = ref(['option1', 'option2'])
const options = [
{
label: 'Success Tag',
value: 'option1',
tagProps: {
color: 'success',
round: true,
},
},
{
label: 'Interactive Tag',
value: 'option2',
tagProps: {
color: 'primary',
interactive: true,
count: 3,
},
},
{
label: 'Tag with Custom Avatar',
value: 'option3',
tagProps: {
color: 'blue',
avatarProps: {
size: 'xs',
objectFit: 'cover',
round: true,
src: 'https://example.com/avatar.jpg',
indicator: true,
name: 'Custom Avatar',
},
},
},
{
label: 'Disabled Tag',
value: 'option4',
tagProps: {
color: 'gray',
disabled: true,
closable: false,
},
},
]
const handleChange = value => {
selectedValue.value = value
}
</script>Available tagProps Options
| Property | Type | Description | Default |
|---|---|---|---|
color | HLTagColor | Tag color variant | 'gray' |
size | 'lg' | 'md' | 'sm' | 'xs' | Tag size | Based on select size |
round | boolean | Rounded appearance | false |
bordered | boolean | Show border | true |
interactive | boolean | Interactive states | true |
disabled | boolean | Disabled state | false |
closable | boolean | Show close button | true |
count | number | Display count in tag | undefined |
dropdown | 'open' | 'close' | false | Dropdown indicator | false |
truncate | boolean | Truncate long text | false |
maxWidth | string | number | Max width for truncation | 136 |
checkbox | boolean | Show checkbox | false |
checked | boolean | Checked state | false |
avatarProps | HLAvatarProps | Avatar configuration | undefined |
Avatar Configuration
The avatarProps property allows you to customize avatar appearance in tags:
{
label: 'User with Custom Avatar',
value: 'user1',
tagProps: {
color: 'primary',
avatarProps: {
size: 'xs', // Avatar size
objectFit: 'cover', // How image fits in avatar
round: true, // Rounded avatar
src: 'https://example.com/user.jpg', // Avatar image URL
indicator: true, // Show online indicator
name: 'John Doe', // Custom name (overrides label)
},
},
}Migration from tagColor
The tagColor prop is deprecated but still supported for backward compatibility:
// Old way (deprecated but still works)
{
label: "Option",
value: "opt1",
tagColor: "primary"
}
// New way (recommended)
{
label: "Option",
value: "opt1",
tagProps: {
color: "primary"
}
}Teleport Select
By default, the select dropdown menu is rendered within its parent component's DOM tree. However, this can cause styling and positioning issues, especially when the select is used inside containers with overflow: hidden, fixed positioning, or complex z-index stacking contexts (like modals, dialogs, or fixed sidebars).
The to prop allows you to teleport (move) the dropdown menu to a different location in the DOM tree, outside of its parent component. This ensures the dropdown remains visible and correctly positioned, regardless of its parent container's styling constraints.
You can specify the target location using:
- A CSS selector (e.g.,
to="#select-teleport-target") falseto disable teleportingtrueto teleport to the default location (body)
<div id="select-teleport-target"></div>
<HLSelect :options="options" :value="selectedValue" @update:value="handleChange" to="#select-teleport-target" id="select-teleport" />Custom Rendering
The select component provides powerful customization options through renderOption and tagRenderer props. These allow you to customize both how options appear in the dropdown menu and how selected values are displayed as tags.
How Custom Rendering Works
Render Option (
renderOption):- Customizes how the option appear in the dropdown menu
- Can return plain text or complex Vue components
- Has access to the full option object including custom properties
Tag Rendering (
tagRenderer):- Single Selection: Completely customizes how the selected value appears in the input
- Multiple Selection: Customizes the content inside the tag wrapper, but the tag wrapper itself remains unchanged
- The tag wrapper (
HLTagcomponent) is always present in multiple selection mode - Only the content within the tag can be customized via
tagRenderer
Option Properties:
label: The display text or componentvalue: The underlying valuetagRenderer: Optional custom tag renderingrenderOption: Optional custom label renderingdescription: Additional text shown below the label- Custom styling properties (backgroundColor, color, etc.)
Option Renderer:
- Customizes how a option appear in the dropdown menu
- Can return plain text or complex Vue components
- It will have parameter
option
<script setup>
import { h } from 'vue'
import { HLSpace, HLIcon, HLAvatar, HLTag, HLText } from '@platform-ui/highrise'
import { CheckVerified01Icon } from '@gohighlevel/ghl-icons/24/outline'
const customOptions = [
{
type: 'group',
label: 'Custom Rendering Examples',
key: 'custom-group',
children: [
{
label: 'Custom Label with Tag',
value: 'option1',
tagRenderer: 'Custom Tag',
backgroundColor: 'var(--green-50)',
color: 'var(--green-700)',
renderOption: () =>
h('div', { class: 'flex items-center gap-2' }, [
h('div', 'Custom Label'),
h(HLTag, { size: 'sm', round: true, variant: 'error' }, { default: () => '2% increase' }),
]),
},
{
label: 'Verified Option',
value: 'option2',
description: 'With icon and description',
backgroundColor: 'var(--purple-50)',
color: 'var(--purple-700)',
renderOption: () =>
h(
HLSpace,
{ align: 'center', wrapItem: false },
{
default: () => [h(HLIcon, { size: 'sm' }, { default: () => h(CheckVerified01Icon) }), h('span', 'Verified Option')],
}
),
},
{
label: 'USA',
value: 'option3',
backgroundColor: 'var(--orange-50)',
color: 'var(--orange-700)',
renderOption: () =>
h(
HLSpace,
{ align: 'center', wrapItem: false, justify: 'space-between' },
{
default: () => [
h(
HLSpace,
{ align: 'center', wrapItem: false },
{
default: () => [
h(HLAvatar, {
size: 'xs',
src: 'https://upload.wikimedia.org/wikipedia/en/thumb/a/a4/Flag_of_the_United_States.svg/1920px-Flag_of_the_United_States.svg.png',
}),
h('span', 'USA'),
],
}
),
h(HLText, { size: 'xs' }, { default: () => '+1' }),
],
}
),
tagRenderer: () =>
h(
HLSpace,
{ align: 'center', wrapItem: false },
{
default: () => [
h('img', {
style: { width: '16px', height: '16px', borderRadius: '50%' },
src: 'https://upload.wikimedia.org/wikipedia/en/thumb/a/a4/Flag_of_the_United_States.svg/1920px-Flag_of_the_United_States.svg.png',
}),
h('span', 'USA'),
],
}
),
},
],
},
]
const optionRenderer = option => {
if (option.renderOption) {
return option.renderOption()
}
return h('span', option.label)
}
</script>
<template>
<HLSelect
:options="customOptions"
:value="selectedValue"
@update:value="handleChange"
:option-renderer="optionRenderer"
multiple
filterable
id="select-custom-render"
/>
</template>Imports
import { HLSelect } from '@platform-ui/highrise'Props
| Prop | Type | Default | Description |
|---|---|---|---|
| id * | string | undefined | Unique identifier for the select |
| allowTagTruncation | boolean | false | Enable truncation of tag text in multiple select mode with ellipsis |
| disabled | boolean | undefined | undefined | Disables the select |
| filterable | boolean | undefined | undefined | Enables search/filter functionality |
| inline | boolean | false | Use inline styling |
| loading | boolean | undefined | undefined | Shows loading state |
| maxTagCount | number | 'responsive' | 'responsive' | Maximum number of visible tags |
| maxTagWidth | string | number | 136 | Maximum width for truncated tags (in pixels if number, or CSS units if string) |
| menuProps | HTMLAttributes | {} | Additional props to pass to the dropdown menu |
| multiple | boolean | false | Enables multiple selection |
| optionHeight | number | undefined | undefined | Height of each option in pixels |
| optionRenderer | (option: SelectOption) => VNodeChild | undefined | undefined | Custom function to render options |
| options | SelectOption[] | [] | Array of options to display |
| placeholder | string | undefined | undefined | Placeholder text when no selection |
| remote | boolean | false | Enable remote search mode. When true, the component will emit search events instead of filtering options locally. Required for async data fetching scenarios. |
| resetMenuOnOptionsChange | boolean | false | Controls whether the dropdown menu position resets when options array changes. Set to true for dynamic content scenarios where menu positioning needs to update. |
| roundedTags | boolean | false | Use rounded styling for tags |
| show | boolean | undefined | undefined | Controls dropdown visibility |
| showArrow | boolean | undefined | undefined | Show/hide dropdown arrow |
| showAvatarInTags | boolean | true | Show avatar in multiple selection tags |
| showCheckmark | boolean | undefined | undefined | Show/hide option checkmark |
| showInlineBottomBorder | boolean | false | Show bottom border in inline mode |
| showInlineCTA | boolean | false | Show confirm/cancel buttons in inline mode |
| showSavedMark | boolean | false | Show saved mark in inline mode |
| showSearchIcon | boolean | false | Shows search icon in input |
| size | 'lg' | 'md' | 'sm' | 'xs' | '2xs' | '3xs' | md | Size of the select |
| to | string | boolean | HTMLElement | undefined | undefined | Teleport dropdown to element/disable |
| triggerFontSize | HLTextSize | undefined | Font size for the trigger text |
| triggerFontWeight | HLTextWeight | undefined | Font weight for the trigger text |
| type | 'default' | 'avatar' | 'default' | Visual style variant |
| value | string | string[] | null | undefined | Selected value(s) |
| valueField | string | 'value' | Field name to use as the value in options |
| wrapperClass | string | undefined | Additional CSS class for the wrapper element |
Types
SelectOption
The options prop accepts an array of SelectOption objects.
interface SelectOption {
description?: string // Optional description text for the option
label?: string | (() => VNodeChild) // Option label text or render function
/** @deprecated Use tagProps.color instead */
tagColor?: HLTagColor // Color of the tag (when used in tags mode)
src?: string // Source URL (e.g. for avatar images)
tagRenderer?: () => VNodeChild // Custom tag render function (content inside tag only)
type: HLSelectOptionType // Type of the option ('group' | 'divider')
value?: string | number // The value of the option
/** Complete tag props object for full control over tag rendering */
tagProps?: SelectTagProps // Advanced tag configuration
}
interface SelectTagProps {
size?: 'lg' | 'md' | 'sm' | 'xs' // Tag size
color?: HLTagColor // Tag color
bordered?: boolean // Whether tag has border
checkbox?: boolean // Whether tag has checkbox
checked?: boolean // Whether tag is checked (if checkbox)
closable?: boolean // Whether tag can be closed
disabled?: boolean // Whether tag is disabled
round?: boolean // Whether tag is rounded
count?: number // Count to display in tag
dropdown?: 'open' | 'close' | false // Dropdown state
interactive?: boolean // Whether tag is interactive
truncate?: boolean // Whether to truncate text
maxWidth?: string | number // Maximum width for truncated text
avatarProps?: any // Avatar props (HLAvatarProps)
}Group Option
When type is 'group', the option can include children:
interface SelectGroupOption extends SelectOption {
type: 'group'
label: string // Group header text
key: string // Unique identifier for the group
children: SelectOption[] // Array of child options
}Divider Option
When type is 'divider', it renders a horizontal line separator:
interface SelectDividerOption {
type: 'divider'
}Examples
// Basic option
{
label: "Option 1",
value: "opt1",
description: "Optional description"
}// Group with children
{
type: "group",
label: "Group 1",
key: "group1",
children: [
{ label: "Child 1", value: "child1" },
{ type: "divider" },
{ label: "Child 2", value: "child2" }
]
}// Tag Renderer
{
label: "Option 1",
value: "opt1",
tagRenderer: () => h(HLTag, { color: "blue" }, "Tag Content")
}Emits
| Name | Parameters | Description |
|---|---|---|
@update:value | (value: string, option: SelectOption) | Triggered when selection changes |
@update:show | (value: boolean) | Triggered when dropdown visibility changes |
@scroll | (e: Event) | Triggered on dropdown scroll |
@search | (value: string) | Triggered when search input changes |
@clear | () | Triggered when selection is cleared |
@focus | () | Triggered when input is focused |
@blur | () | Triggered when input is blurred |
Methods
| Name | Parameters | Description |
|---|---|---|
focusInput | () | Focuses the input field |
blurInput | () | Blurs the input field |
focus | () | Focuses the select |
blur | () | Blurs the select |
Slots
| Name | Parameters | Description |
|---|---|---|
| default | () | The default content slot |
| icon | () | Custom icon slot |
| header | () | Header content for dropdown |
| action | () | Action content for dropdown |
| arrow | () | Custom arrow icon |
| empty | () | Content when no options exist |
| edit-actions | () | Edit actions content for inline mode |