AJAX Search Examples
Basic AJAX Search
Load options from a remote API as the user types:
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/users?q={@term}"
data-placeholder="Search users..."
>
</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-ajax-url="/api/users?q={@term}"
data-placeholder="Search users..."
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/users?q={@term}"
data-placeholder="Search users..."
>
</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>With Field Mapping
Map custom API response fields to DotSelect's expected format:
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/products?search={@term}"
data-option-id="product_id"
data-option-text="product_name"
data-placeholder="Search products..."
>
</select>import { DotSelect } from 'dot-select'
const ds = new DotSelect('#product_id')
// 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-ajax-url="/api/products?search={@term}"
data-option-id="product_id"
data-option-text="product_name"
data-placeholder="Search products..."
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/products?search={@term}"
data-option-id="product_id"
data-option-text="product_name"
data-placeholder="Search products..."
>
</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>Expected API response:
{
"data": [
{ "product_id": "SKU001", "product_name": "Wireless Mouse" },
{ "product_id": "SKU002", "product_name": "Mechanical Keyboard" }
]
}With Custom Templates
Display rich option content with avatars and metadata:
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/users?q={@term}"
data-render-option-content-as-html="true"
data-render-item-content-as-html="true"
data-template-option="<div style='display:flex;align-items:center;gap:10px'><img src='{@avatar_url}' style='width:32px;height:32px;border-radius:50%'/><div><strong>{@text}</strong><br/><small style='color:#6b7280'>{@email}</small></div></div>"
data-template-item="<span><img src='{@avatar_url}' style='width:18px;height:18px;border-radius:50%;vertical-align:middle;margin-right:4px'/>{@text}</span>"
data-placeholder="Search users..."
data-allow-clear="true"
>
</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-ajax-url="/api/users?q={@term}"
data-render-option-content-as-html="true"
data-render-item-content-as-html="true"
data-template-option="<div style='display:flex;align-items:center;gap:10px'><img src='{@avatar_url}' style='width:32px;height:32px;border-radius:50%'/><div><strong>{@text}</strong><br/><small style='color:#6b7280'>{@email}</small></div></div>"
data-template-item="<span><img src='{@avatar_url}' style='width:18px;height:18px;border-radius:50%;vertical-align:middle;margin-right:4px'/>{@text}</span>"
data-placeholder="Search users..."
data-allow-clear="true"
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/users?q={@term}"
data-render-option-content-as-html="true"
data-render-item-content-as-html="true"
data-template-option="<div style='display:flex;align-items:center;gap:10px'><img src='{@avatar_url}' style='width:32px;height:32px;border-radius:50%'/><div><strong>{@text}</strong><br/><small style='color:#6b7280'>{@email}</small></div></div>"
data-template-item="<span><img src='{@avatar_url}' style='width:18px;height:18px;border-radius:50%;vertical-align:middle;margin-right:4px'/>{@text}</span>"
data-placeholder="Search users..."
data-allow-clear="true"
>
</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>Minimum Characters
Require a minimum number of characters before searching:
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/customers?q={@term}"
data-ajax-min-chars="3"
data-input-too-short-text="Type at least 3 characters to search"
data-placeholder="Type 3+ characters to search customers..."
>
</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-ajax-url="/api/customers?q={@term}"
data-ajax-min-chars="3"
data-input-too-short-text="Type at least 3 characters to search"
data-placeholder="Type 3+ characters to search customers..."
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/customers?q={@term}"
data-ajax-min-chars="3"
data-input-too-short-text="Type at least 3 characters to search"
data-placeholder="Type 3+ characters to search customers..."
>
</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>Custom Debounce Delay
Reduce or increase the delay before sending the AJAX request:
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/addresses?q={@term}"
data-ajax-delay="500"
data-placeholder="Search 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-ajax-url="/api/addresses?q={@term}"
data-ajax-delay="500"
data-placeholder="Search addresses..."
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/addresses?q={@term}"
data-ajax-delay="500"
data-placeholder="Search 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>With Authentication Headers
Send authorization tokens with AJAX requests:
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/secure/projects?q={@term}"
data-ajax-headers='{"Authorization": "Bearer eyJhbGciOiJIUzI1NiIs...", "Accept": "application/json"}'
data-placeholder="Search projects..."
>
</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-ajax-url="/api/secure/projects?q={@term}"
data-ajax-headers='{"Authorization": "Bearer eyJhbGciOiJIUzI1NiIs...", "Accept": "application/json"}'
data-placeholder="Search projects..."
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/secure/projects?q={@term}"
data-ajax-headers='{"Authorization": "Bearer eyJhbGciOiJIUzI1NiIs...", "Accept": "application/json"}'
data-placeholder="Search projects..."
>
</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>Multiple Select with AJAX
Search and select multiple remote items:
<select
data-dot-select
data-searchable="true"
data-plugins="remove-button"
data-ajax-url="/api/tags?q={@term}&exclude={@selected}"
data-placeholder="Search and add tags..."
multiple
>
</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-plugins="remove-button"
data-ajax-url="/api/tags?q={@term}&exclude={@selected}"
data-placeholder="Search and add tags..."
multiple
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-plugins="remove-button"
data-ajax-url="/api/tags?q={@term}&exclude={@selected}"
data-placeholder="Search and add tags..."
multiple
>
</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
Using {@selected} in the URL lets the server exclude already-selected items from the search results.
Pre-Selected AJAX Values
Load a form with pre-selected values that need display text from the server:
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/users?q={@term}"
data-ajax-resolve-url="/api/users/resolve?ids={@selected}"
data-selected="42,87,103"
data-plugins="remove-button"
data-placeholder="Search users..."
multiple
>
</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-ajax-url="/api/users?q={@term}"
data-ajax-resolve-url="/api/users/resolve?ids={@selected}"
data-selected="42,87,103"
data-plugins="remove-button"
data-placeholder="Search users..."
multiple
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/users?q={@term}"
data-ajax-resolve-url="/api/users/resolve?ids={@selected}"
data-selected="42,87,103"
data-plugins="remove-button"
data-placeholder="Search users..."
multiple
>
</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>DotSelect calls /api/users/resolve?ids=42,87,103 on initialization to fetch display text for the pre-selected IDs.
Custom Data Key
Handle APIs that nest results under a different key:
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/v2/search?type=employee&q={@term}"
data-ajax-data-key="response.results"
data-placeholder="Search employees..."
>
</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-ajax-url="/api/v2/search?type=employee&q={@term}"
data-ajax-data-key="response.results"
data-placeholder="Search employees..."
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/v2/search?type=employee&q={@term}"
data-ajax-data-key="response.results"
data-placeholder="Search employees..."
>
</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>Expected API response:
{
"response": {
"results": [
{ "id": 1, "text": "Alice Johnson" },
{ "id": 2, "text": "Bob Smith" }
],
"total": 42
}
}POST Request
Use POST method for search requests:
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/search"
data-ajax-method="POST"
data-placeholder="Search..."
>
</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-ajax-url="/api/search"
data-ajax-method="POST"
data-placeholder="Search..."
>
</select>
)
}<template>
<select
data-dot-select
data-searchable="true"
data-ajax-url="/api/search"
data-ajax-method="POST"
data-placeholder="Search..."
>
</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>