Skip to content

Custom Rendering

Every component in vue-superselect exposes scoped slots for rendering custom content. The library is headless, so these demos show one possible styling approach. You have full control over what each option and tag looks like.

Rich Option Content

Use the SelectOption default slot to render icons, badges, secondary text, or any custom layout inside each option.

Custom Option Rendering with Icons and Categories

Scoped Slot Props

SelectOption provides these scoped slot props for conditional rendering and styling:

template
<SelectOption v-slot="{ selected, active, disabled, option }">
  <!-- Render anything here -->
</SelectOption>
PropTypeDescription
selectedbooleanWhether this option is currently selected
activebooleanWhether this option is keyboard-highlighted
disabledbooleanWhether this option is disabled
optionunknownThe raw value passed to :value
vue
<script setup>
import { ref } from 'vue'
import { SelectRoot, SelectControl, SelectInput, SelectContent, SelectOption } from 'vue-superselect'

const selected = ref(null)
const languages = [
  { id: 'js', name: 'JavaScript', icon: 'JS', category: 'Frontend' },
  { id: 'ts', name: 'TypeScript', icon: 'TS', category: 'Frontend' },
  { id: 'python', name: 'Python', icon: 'Py', category: 'Backend' },
]
</script>

<template>
  <SelectRoot v-model="selected" :items="languages" label-key="name" value-key="id">
    <SelectControl>
      <SelectInput placeholder="Pick a language..." />
    </SelectControl>
    <SelectContent>
      <SelectOption
        v-for="lang in languages"
        :key="lang.id"
        :value="lang.id"
        :label="lang.name"
        v-slot="{ selected: isSelected, active }"
      >
        <span class="icon">{{ lang.icon }}</span>
        <span class="info">
          <span>{{ lang.name }}</span>
          <span class="category">{{ lang.category }}</span>
        </span>
        <span v-if="isSelected">&#10003;</span>
      </SelectOption>
    </SelectContent>
  </SelectRoot>
</template>

Custom Tags and Selected Display

Use SelectControl's scoped slot to customize how selected items are displayed. Combined with SelectTag's scoped slot, you can render avatars, custom remove buttons, or any layout inside tags.

Custom Tags with Avatars

SelectControl Scoped Slot

SelectControl provides data about the current selection:

template
<SelectControl v-slot="{ selectedItems, removeItem, multiple }">
  <!-- Render selected items however you want -->
</SelectControl>
Slot DataTypeDescription
selectedItems{ value: unknown; label: string }[]Currently selected items with resolved labels
removeItem(value: unknown) => voidRemoves an item from the selection
multiplebooleanWhether multi-select mode is active

SelectTag Scoped Slot

Each SelectTag can be fully customized with its own scoped slot:

template
<SelectTag :value="item.value" :label="item.label" v-slot="{ label, remove }">
  <span class="avatar">{{ getInitials(item) }}</span>
  <span>{{ label }}</span>
  <button @click="remove">&times;</button>
</SelectTag>
Slot DataTypeDescription
labelstringThe resolved label for this tag
remove() => voidRemoves this specific tag

Styling with Data Attributes

Every component renders data attributes that reflect the current state, enabling CSS-only styling without scoped slot props:

css
/* Highlighted option */
[data-highlighted="true"] {
  background-color: #e0f2fe;
}

/* Selected option */
[data-selected="true"] {
  font-weight: 600;
  color: #2563eb;
}

/* Disabled option */
[data-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
}

Available data attributes on SelectOption:

AttributeValuesDescription
data-selected"true" | "false"Whether the option is selected
data-highlighted"true" | "false"Whether the option has keyboard focus
data-disabled"true" | "false"Whether the option is disabled

On SelectRoot:

AttributeValuesDescription
data-state"open" | "closed"Whether the dropdown is open
data-disabled"true" | undefinedWhether the component is disabled

Data attributes are useful when you want to style options without writing JavaScript logic in scoped slots. For example, a CSS-only approach with Tailwind or utility classes.

Next Steps