|
| 1 | +--- |
| 2 | +title: 'Custom tag content slot' |
| 3 | +--- |
| 4 | + |
| 5 | +# Custom tag content slot |
| 6 | + |
| 7 | +The following example demonstrates how to use the `VueSelect` component with the `#tag-content` slot when using the `isMulti` prop. |
| 8 | + |
| 9 | +## What is the `#tag-content` slot? |
| 10 | + |
| 11 | +The `#tag-content` slot allows you to customize only the text content inside a multi-select tag, while automatically preserving: |
| 12 | + |
| 13 | +- The tag wrapper structure |
| 14 | +- Default styling (background, padding, borders) |
| 15 | +- The remove button |
| 16 | +- Event handlers for removing tags |
| 17 | + |
| 18 | +This makes it much simpler than the `#tag` slot when you only want to change how the label text is displayed. |
| 19 | + |
| 20 | +## When to use `#tag-content` vs `#tag` |
| 21 | + |
| 22 | +### Use `#tag-content` when: |
| 23 | +- You only want to format or transform the label text |
| 24 | +- You want to add icons, badges, or emphasis to the text |
| 25 | +- You want to keep the default tag styling and remove button |
| 26 | + |
| 27 | +### Use `#tag` when: |
| 28 | +- You need complete control over the tag structure |
| 29 | +- You want custom styling that can't be achieved with CSS variables |
| 30 | +- You need to change the remove button appearance or behavior |
| 31 | + |
| 32 | +::: info |
| 33 | +Read more about available [slots here](../slots.md), the `#tag` slot [here](./custom-tag-slot.md), and the `isMulti` prop [here](../props.md#isMulti). |
| 34 | +::: |
| 35 | + |
| 36 | +<script setup> |
| 37 | +import { ref } from "vue"; |
| 38 | +import VueSelect from "../../src"; |
| 39 | + |
| 40 | +const selected = ref([]); |
| 41 | + |
| 42 | +const skillOptions = [ |
| 43 | + { label: "JavaScript", value: "javascript", level: "expert", icon: "🟨" }, |
| 44 | + { label: "TypeScript", value: "typescript", level: "expert", icon: "🔷" }, |
| 45 | + { label: "Vue.js", value: "vue", level: "expert", icon: "💚" }, |
| 46 | + { label: "React", value: "react", level: "intermediate", icon: "⚛️" }, |
| 47 | + { label: "Python", value: "python", level: "beginner", icon: "🐍" }, |
| 48 | + { label: "Rust", value: "rust", level: "beginner", icon: "🦀" }, |
| 49 | +]; |
| 50 | + |
| 51 | +const levelColors = { |
| 52 | + beginner: "#93c5fd", |
| 53 | + intermediate: "#86efac", |
| 54 | + expert: "#fde047", |
| 55 | +}; |
| 56 | +</script> |
| 57 | + |
| 58 | +<ClientOnly> |
| 59 | + <VueSelect |
| 60 | + v-model="selected" |
| 61 | + :is-multi="true" |
| 62 | + :options="skillOptions" |
| 63 | + placeholder="Select your skills" |
| 64 | + > |
| 65 | + <template #tag-content="{ option }"> |
| 66 | + <span :style="{ display: 'flex', alignItems: 'center', gap: '4px' }"> |
| 67 | + <span>{{ option.icon }}</span> |
| 68 | + <strong>{{ option.label }}</strong> |
| 69 | + <span |
| 70 | + :style="{ |
| 71 | + fontSize: '10px', |
| 72 | + padding: '2px 4px', |
| 73 | + borderRadius: '2px', |
| 74 | + backgroundColor: levelColors[option.level], |
| 75 | + color: '#000', |
| 76 | + fontWeight: 500, |
| 77 | + }" |
| 78 | + > |
| 79 | + {{ option.level }} |
| 80 | + </span> |
| 81 | + </span> |
| 82 | + </template> |
| 83 | + </VueSelect> |
| 84 | +</ClientOnly> |
| 85 | + |
| 86 | +## Demo source-code |
| 87 | + |
| 88 | +```vue |
| 89 | +<script setup> |
| 90 | +import { ref } from "vue"; |
| 91 | +import VueSelect from "vue3-select-component"; |
| 92 | +
|
| 93 | +const selected = ref([]); |
| 94 | +
|
| 95 | +const skillOptions = [ |
| 96 | + { label: "JavaScript", value: "javascript", level: "expert", icon: "🟨" }, |
| 97 | + { label: "TypeScript", value: "typescript", level: "expert", icon: "🔷" }, |
| 98 | + { label: "Vue.js", value: "vue", level: "expert", icon: "💚" }, |
| 99 | + { label: "React", value: "react", level: "intermediate", icon: "⚛️" }, |
| 100 | + { label: "Python", value: "python", level: "beginner", icon: "🐍" }, |
| 101 | + { label: "Rust", value: "rust", level: "beginner", icon: "🦀" }, |
| 102 | +]; |
| 103 | +
|
| 104 | +const levelColors = { |
| 105 | + beginner: "#93c5fd", |
| 106 | + intermediate: "#86efac", |
| 107 | + expert: "#fde047", |
| 108 | +}; |
| 109 | +</script> |
| 110 | +
|
| 111 | +<template> |
| 112 | + <VueSelect |
| 113 | + v-model="selected" |
| 114 | + :is-multi="true" |
| 115 | + :options="skillOptions" |
| 116 | + placeholder="Select your skills" |
| 117 | + > |
| 118 | + <template #tag-content="{ option }"> |
| 119 | + <span :style="{ display: 'flex', alignItems: 'center', gap: '4px' }"> |
| 120 | + <span>{{ option.icon }}</span> |
| 121 | + <strong>{{ option.label }}</strong> |
| 122 | + <span |
| 123 | + :style="{ |
| 124 | + fontSize: '10px', |
| 125 | + padding: '2px 4px', |
| 126 | + borderRadius: '2px', |
| 127 | + backgroundColor: levelColors[option.level], |
| 128 | + color: '#000', |
| 129 | + fontWeight: 500, |
| 130 | + }" |
| 131 | + > |
| 132 | + {{ option.level }} |
| 133 | + </span> |
| 134 | + </span> |
| 135 | + </template> |
| 136 | + </VueSelect> |
| 137 | +</template> |
| 138 | +``` |
| 139 | + |
| 140 | +## Key Benefits |
| 141 | + |
| 142 | +1. **Simpler Implementation**: No need to recreate the tag structure or remove button |
| 143 | +2. **Consistent Styling**: Automatically inherits all CSS variables for tags |
| 144 | +3. **Type Safety**: Full TypeScript support with option typing |
| 145 | +4. **Less Code**: Focus only on the content formatting |
| 146 | +5. **Maintainability**: Future component updates automatically apply |
| 147 | + |
| 148 | +## Comparison: `#tag` vs `#tag-content` |
| 149 | + |
| 150 | +### With `#tag-content` (Simpler) |
| 151 | + |
| 152 | +```html |
| 153 | +<template #tag-content="{ option }"> |
| 154 | + <strong>{{ option.label }}</strong> |
| 155 | +</template> |
| 156 | +``` |
| 157 | + |
| 158 | +The component handles: |
| 159 | +- Tag wrapper (`<div class="multi-value">`) |
| 160 | +- Remove button with icon |
| 161 | +- Click handlers |
| 162 | +- Styling with CSS variables |
| 163 | + |
| 164 | +### With `#tag` (Full Control) |
| 165 | + |
| 166 | +```html |
| 167 | +<template #tag="{ option, removeOption }"> |
| 168 | + <div class="custom-tag"> |
| 169 | + <strong>{{ option.label }}</strong> |
| 170 | + <button @click="removeOption">×</button> |
| 171 | + </div> |
| 172 | +</template> |
| 173 | +``` |
| 174 | + |
| 175 | +You must handle: |
| 176 | +- Complete tag structure |
| 177 | +- Custom button and event handler |
| 178 | +- All styling from scratch |
0 commit comments