Tagging Examples
Basic Tagging
Allow users to create new options by typing:
<select
data-dot-select
data-searchable="true"
data-create-items="true"
multiple
data-placeholder="Type to add tags..."
>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="javascript">JavaScript</option>
</select>import { DotSelect } from 'dot-select'
const ds = new DotSelect('select[data-dot-select]')
// API
ds.getValue()
ds.setValue(['value'])
ds.clear()
ds.destroy()import { useEffect, useRef } from 'react'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
export default function Select() {
const ref = useRef(null)
useEffect(() => {
const ds = new DotSelect(ref.current)
return () => ds.destroy()
}, [])
return (
<select
data-dot-select
data-searchable="true"
data-create-items="true"
multiple
data-placeholder="Type to add tags..."
>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="javascript">JavaScript</option>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-create-items="true"
multiple
data-placeholder="Type to add tags..."
>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="javascript">JavaScript</option>
</select>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
const selectRef = ref(null)
let ds = null
onMounted(() => {
ds = new DotSelect(selectRef.value)
})
onBeforeUnmount(() => {
ds?.destroy()
})
</script>Type a value that does not exist in the list, and an "Add ..." prompt appears. Press Enter to create it.
Tags with Comma Separator
Enable the tags plugin for comma-separated input:
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags"
multiple
data-placeholder="Enter tags separated by commas..."
>
</select>import { DotSelect } from 'dot-select'
const ds = new DotSelect('select[data-dot-select]')
// API
ds.getValue()
ds.setValue(['value'])
ds.clear()
ds.destroy()import { useEffect, useRef } from 'react'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
export default function Select() {
const ref = useRef(null)
useEffect(() => {
const ds = new DotSelect(ref.current)
return () => ds.destroy()
}, [])
return (
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags"
multiple
data-placeholder="Enter tags separated by commas..."
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags"
multiple
data-placeholder="Enter tags separated by commas..."
>
</select>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
const selectRef = ref(null)
let ds = null
onMounted(() => {
ds = new DotSelect(selectRef.value)
})
onBeforeUnmount(() => {
ds?.destroy()
})
</script>Type react, vue, angular and three tags are created at once.
Tags with Remove Buttons
Add remove buttons for easy tag management:
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags,remove-button"
multiple
data-placeholder="Add or remove tags..."
>
<option value="bug" selected>Bug</option>
<option value="feature" selected>Feature</option>
<option value="enhancement">Enhancement</option>
<option value="documentation">Documentation</option>
</select>import { DotSelect } from 'dot-select'
const ds = new DotSelect('select[data-dot-select]')
// API
ds.getValue()
ds.setValue(['value'])
ds.clear()
ds.destroy()import { useEffect, useRef } from 'react'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
export default function Select() {
const ref = useRef(null)
useEffect(() => {
const ds = new DotSelect(ref.current)
return () => ds.destroy()
}, [])
return (
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags,remove-button"
multiple
data-placeholder="Add or remove tags..."
>
<option value="bug" selected>Bug</option>
<option value="feature" selected>Feature</option>
<option value="enhancement">Enhancement</option>
<option value="documentation">Documentation</option>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags,remove-button"
multiple
data-placeholder="Add or remove tags..."
>
<option value="bug" selected>Bug</option>
<option value="feature" selected>Feature</option>
<option value="enhancement">Enhancement</option>
<option value="documentation">Documentation</option>
</select>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
const selectRef = ref(null)
let ds = null
onMounted(() => {
ds = new DotSelect(selectRef.value)
})
onBeforeUnmount(() => {
ds?.destroy()
})
</script>Tags with Existing Options
Combine tagging with pre-defined suggestions:
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags,remove-button"
multiple
data-placeholder="Select or create skills..."
>
<option value="javascript">JavaScript</option>
<option value="python">Python</option>
<option value="java">Java</option>
<option value="csharp">C#</option>
<option value="go">Go</option>
<option value="rust">Rust</option>
<option value="typescript">TypeScript</option>
<option value="ruby">Ruby</option>
<option value="php">PHP</option>
<option value="swift">Swift</option>
</select>import { DotSelect } from 'dot-select'
const ds = new DotSelect('select[data-dot-select]')
// API
ds.getValue()
ds.setValue(['value'])
ds.clear()
ds.destroy()import { useEffect, useRef } from 'react'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
export default function Select() {
const ref = useRef(null)
useEffect(() => {
const ds = new DotSelect(ref.current)
return () => ds.destroy()
}, [])
return (
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags,remove-button"
multiple
data-placeholder="Select or create skills..."
>
<option value="javascript">JavaScript</option>
<option value="python">Python</option>
<option value="java">Java</option>
<option value="csharp">C#</option>
<option value="go">Go</option>
<option value="rust">Rust</option>
<option value="typescript">TypeScript</option>
<option value="ruby">Ruby</option>
<option value="php">PHP</option>
<option value="swift">Swift</option>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags,remove-button"
multiple
data-placeholder="Select or create skills..."
>
<option value="javascript">JavaScript</option>
<option value="python">Python</option>
<option value="java">Java</option>
<option value="csharp">C#</option>
<option value="go">Go</option>
<option value="rust">Rust</option>
<option value="typescript">TypeScript</option>
<option value="ruby">Ruby</option>
<option value="php">PHP</option>
<option value="swift">Swift</option>
</select>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
const selectRef = ref(null)
let ds = null
onMounted(() => {
ds = new DotSelect(selectRef.value)
})
onBeforeUnmount(() => {
ds?.destroy()
})
</script>Users can select existing skills from the dropdown or type new ones.
Custom Create Prompt Text
Change the text shown when creating a new tag:
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-create-items-text="Create tag: {@term}"
data-plugins="tags,remove-button"
multiple
data-placeholder="Enter email addresses..."
>
</select>import { DotSelect } from 'dot-select'
const ds = new DotSelect('select[data-dot-select]')
// API
ds.getValue()
ds.setValue(['value'])
ds.clear()
ds.destroy()import { useEffect, useRef } from 'react'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
export default function Select() {
const ref = useRef(null)
useEffect(() => {
const ds = new DotSelect(ref.current)
return () => ds.destroy()
}, [])
return (
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-create-items-text="Create tag: {@term}"
data-plugins="tags,remove-button"
multiple
data-placeholder="Enter email addresses..."
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-create-items-text="Create tag: {@term}"
data-plugins="tags,remove-button"
multiple
data-placeholder="Enter email addresses..."
>
</select>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
const selectRef = ref(null)
let ds = null
onMounted(() => {
ds = new DotSelect(selectRef.value)
})
onBeforeUnmount(() => {
ds?.destroy()
})
</script>Tags with Validation
Restrict new tag values using a regex pattern:
<!-- Only allow valid email addresses -->
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-create-items-pattern="^[^\s@]+@[^\s@]+\.[^\s@]+$"
data-create-items-text="Add email: {@term}"
data-plugins="tags,remove-button"
multiple
data-placeholder="Enter email addresses..."
>
</select>import { DotSelect } from 'dot-select'
const ds = new DotSelect('select[data-dot-select]')
// API
ds.getValue()
ds.setValue(['value'])
ds.clear()
ds.destroy()import { useEffect, useRef } from 'react'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
export default function Select() {
const ref = useRef(null)
useEffect(() => {
const ds = new DotSelect(ref.current)
return () => ds.destroy()
}, [])
return (
<!-- Only allow valid email addresses -->
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-create-items-pattern="^[^\s@]+@[^\s@]+\.[^\s@]+$"
data-create-items-text="Add email: {@term}"
data-plugins="tags,remove-button"
multiple
data-placeholder="Enter email addresses..."
>
</select>
)
}<template>
<!-- Only allow valid email addresses -->
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-create-items-pattern="^[^\s@]+@[^\s@]+\.[^\s@]+$"
data-create-items-text="Add email: {@term}"
data-plugins="tags,remove-button"
multiple
data-placeholder="Enter email addresses..."
>
</select>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
const selectRef = ref(null)
let ds = null
onMounted(() => {
ds = new DotSelect(selectRef.value)
})
onBeforeUnmount(() => {
ds?.destroy()
})
</script>TIP
The "Add" prompt only appears when the typed value matches the pattern. If a user types something invalid, no creation option is shown.
Tags with Custom Separator
Use semicolons instead of commas:
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags,remove-button"
data-tags-separator=";"
multiple
data-placeholder="Separate with semicolons..."
>
</select>import { DotSelect } from 'dot-select'
const ds = new DotSelect('select[data-dot-select]')
// API
ds.getValue()
ds.setValue(['value'])
ds.clear()
ds.destroy()import { useEffect, useRef } from 'react'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
export default function Select() {
const ref = useRef(null)
useEffect(() => {
const ds = new DotSelect(ref.current)
return () => ds.destroy()
}, [])
return (
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags,remove-button"
data-tags-separator=";"
multiple
data-placeholder="Separate with semicolons..."
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags,remove-button"
data-tags-separator=";"
multiple
data-placeholder="Separate with semicolons..."
>
</select>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
const selectRef = ref(null)
let ds = null
onMounted(() => {
ds = new DotSelect(selectRef.value)
})
onBeforeUnmount(() => {
ds?.destroy()
})
</script>Tags with AJAX Search
Combine tagging with remote search — users can find existing items or create new ones:
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-ajax-url="/api/tags?q={@term}"
data-plugins="tags,remove-button"
multiple
data-placeholder="Search existing or create new tags..."
>
</select>import { DotSelect } from 'dot-select'
const ds = new DotSelect('select[data-dot-select]')
// API
ds.getValue()
ds.setValue(['value'])
ds.clear()
ds.destroy()import { useEffect, useRef } from 'react'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
export default function Select() {
const ref = useRef(null)
useEffect(() => {
const ds = new DotSelect(ref.current)
return () => ds.destroy()
}, [])
return (
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-ajax-url="/api/tags?q={@term}"
data-plugins="tags,remove-button"
multiple
data-placeholder="Search existing or create new tags..."
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-ajax-url="/api/tags?q={@term}"
data-plugins="tags,remove-button"
multiple
data-placeholder="Search existing or create new tags..."
>
</select>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
const selectRef = ref(null)
let ds = null
onMounted(() => {
ds = new DotSelect(selectRef.value)
})
onBeforeUnmount(() => {
ds?.destroy()
})
</script>Paste Support
The tags plugin automatically handles paste events. Try pasting comma-separated values:
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags,remove-button"
multiple
data-placeholder="Paste comma-separated values here..."
>
</select>import { DotSelect } from 'dot-select'
const ds = new DotSelect('select[data-dot-select]')
// API
ds.getValue()
ds.setValue(['value'])
ds.clear()
ds.destroy()import { useEffect, useRef } from 'react'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
export default function Select() {
const ref = useRef(null)
useEffect(() => {
const ds = new DotSelect(ref.current)
return () => ds.destroy()
}, [])
return (
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags,remove-button"
multiple
data-placeholder="Paste comma-separated values here..."
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-create-items="true"
data-plugins="tags,remove-button"
multiple
data-placeholder="Paste comma-separated values here..."
>
</select>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
const selectRef = ref(null)
let ds = null
onMounted(() => {
ds = new DotSelect(selectRef.value)
})
onBeforeUnmount(() => {
ds?.destroy()
})
</script>Paste alpha, beta, gamma, delta and four tags are created instantly.
Full-Featured Tagging
A complete tagging setup for a form field:
<div class="form-group">
<label for="project-tags">Project Tags</label>
<select
id="project-tags"
name="tags[]"
data-dot-select
data-searchable="true"
data-create-items="true"
data-create-items-text="Create: {@term}"
data-create-items-pattern="^[a-zA-Z0-9][a-zA-Z0-9._-]*$"
data-plugins="tags,remove-button,clear-button"
data-ajax-url="/api/tags?q={@term}"
data-allow-clear="true"
data-placeholder="Search or create tags..."
multiple
>
<option value="v1.0" selected>v1.0</option>
<option value="production" selected>production</option>
</select>
<small class="form-text">Tags must start with a letter or number. Separate multiple tags with commas or paste them.</small>
</div>import { DotSelect } from 'dot-select'
const ds = new DotSelect('#project-tags')
// API
ds.getValue()
ds.setValue(['value'])
ds.clear()
ds.destroy()import { useEffect, useRef } from 'react'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
export default function Select() {
const ref = useRef(null)
useEffect(() => {
const ds = new DotSelect(ref.current)
return () => ds.destroy()
}, [])
return (
<div class="form-group">
<label for="project-tags">Project Tags</label>
<select
id="project-tags"
name="tags[]"
data-dot-select
data-searchable="true"
data-create-items="true"
data-create-items-text="Create: {@term}"
data-create-items-pattern="^[a-zA-Z0-9][a-zA-Z0-9._-]*$"
data-plugins="tags,remove-button,clear-button"
data-ajax-url="/api/tags?q={@term}"
data-allow-clear="true"
data-placeholder="Search or create tags..."
multiple
>
<option value="v1.0" selected>v1.0</option>
<option value="production" selected>production</option>
</select>
<small class="form-text">Tags must start with a letter or number. Separate multiple tags with commas or paste them.</small>
</div>
)
}<template>
<div class="form-group">
<label for="project-tags">Project Tags</label>
<select
id="project-tags"
name="tags[]"
data-dot-select
data-searchable="true"
data-create-items="true"
data-create-items-text="Create: {@term}"
data-create-items-pattern="^[a-zA-Z0-9][a-zA-Z0-9._-]*$"
data-plugins="tags,remove-button,clear-button"
data-ajax-url="/api/tags?q={@term}"
data-allow-clear="true"
data-placeholder="Search or create tags..."
multiple
>
<option value="v1.0" selected>v1.0</option>
<option value="production" selected>production</option>
</select>
<small class="form-text">Tags must start with a letter or number. Separate multiple tags with commas or paste them.</small>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { DotSelect } from 'dot-select'
import 'dot-select/css'
const selectRef = ref(null)
let ds = null
onMounted(() => {
ds = new DotSelect(selectRef.value)
})
onBeforeUnmount(() => {
ds?.destroy()
})
</script>WARNING
When combining tagging with AJAX, newly created tags only exist on the client side. Your backend should handle unknown tag values in the form submission (e.g., by creating new tag records in the database).