I am trying to create a custom select component that can accept options as HTML like this:
<MySelect v-model='value'>
<MyOption value='1'>Option 1</MyOption>
<MyOption value='2'>Option 2</MyOption>
</MySelect>
This is my current implementation of the custom select component:
<template>
<div class="select">
<div class="text" @click="visible=!visible">{{modelValue ?? text}} <IconChevronDown/></div>
<div class="options" v-if="visible">
<span v-for="option in options" class="p-4 hover:bg-neutral-1 cursor-pointer capitalize" @click="select(option)">{{option}}</span>
</div>
</div>
</template>
<script setup>
const visible = ref(false)
const props = defineProps({
text: String,
options: Array,
modelValue: String
})
const emit = defineEmits(["update:modelValue"])
function select(option){
visible.value = false;
emit("update:modelValue", option)
}
</script>
This component accepts options as a prop and just as an array of strings. But I need more customization of options, such as adding an icon or applying styles to text. So, the ability to pass options as HTML would have solved this problem. I would appreciate if you could share your ideas of how this can be implemented!
P.S. MySelect component should not contain native select and option tags. The whole purpose of creating a custom select component is for design customization.
2
Answers
Customizing list items is usually done with scoped slots:
VUE SFC PLAYGROUND
MySelect.vue:
You can also automatically handle the selection click, but for that you need a custom render option slot component. Plus of cause you can use your own component to pass to the slot:
VUE SFC PLAYGROUND
MySelect.vue
MyOption.vue
You can create a custom slot render function and collect default slots of the slotted child components:
VUE SFC PLAYGROUND
Usually I would prefer the scoped slot solution posted in my other answer here, BUT nobody stops from MERGING 2 solutions into 1: using the default slot from here and
#option
from the other answer. So the select component could be fed by both slots.MySelect.vue
MyOption.vue