Chained Select Examples
Static Chain: Country, State, City
A three-level chain using inline static data:
<!-- Country -->
<label>Country</label>
<select
data-dot-select
data-chain-group="location"
data-chained-index="0"
data-placeholder="Select a country..."
>
<option value="">Select a country...</option>
<option value="us">United States</option>
<option value="ca">Canada</option>
<option value="uk">United Kingdom</option>
</select>
<!-- State / Province -->
<label>State / Province</label>
<select
data-dot-select
data-chain-group="location"
data-chained-index="1"
data-chained-disabled-on-empty="true"
data-chained-clear-on-parent-change="true"
data-placeholder="Select a state..."
data-chained-child-data='{
"us": [
{"id": "ca", "text": "California"},
{"id": "ny", "text": "New York"},
{"id": "tx", "text": "Texas"},
{"id": "fl", "text": "Florida"}
],
"ca": [
{"id": "on", "text": "Ontario"},
{"id": "bc", "text": "British Columbia"},
{"id": "qc", "text": "Quebec"},
{"id": "ab", "text": "Alberta"}
],
"uk": [
{"id": "eng", "text": "England"},
{"id": "sct", "text": "Scotland"},
{"id": "wls", "text": "Wales"},
{"id": "nir", "text": "Northern Ireland"}
]
}'
>
</select>
<!-- City -->
<label>City</label>
<select
data-dot-select
data-chain-group="location"
data-chained-index="2"
data-chained-disabled-on-empty="true"
data-chained-clear-on-parent-change="true"
data-placeholder="Select a city..."
data-chained-child-data='{
"ca": [{"id": "la", "text": "Los Angeles"}, {"id": "sf", "text": "San Francisco"}, {"id": "sd", "text": "San Diego"}],
"ny": [{"id": "nyc", "text": "New York City"}, {"id": "buf", "text": "Buffalo"}, {"id": "alb", "text": "Albany"}],
"tx": [{"id": "hou", "text": "Houston"}, {"id": "dal", "text": "Dallas"}, {"id": "aus", "text": "Austin"}],
"fl": [{"id": "mia", "text": "Miami"}, {"id": "orl", "text": "Orlando"}, {"id": "tam", "text": "Tampa"}],
"on": [{"id": "tor", "text": "Toronto"}, {"id": "ott", "text": "Ottawa"}, {"id": "ham", "text": "Hamilton"}],
"bc": [{"id": "van", "text": "Vancouver"}, {"id": "vic", "text": "Victoria"}],
"qc": [{"id": "mtl", "text": "Montreal"}, {"id": "qcc", "text": "Quebec City"}],
"ab": [{"id": "cal", "text": "Calgary"}, {"id": "edm", "text": "Edmonton"}],
"eng": [{"id": "lon", "text": "London"}, {"id": "man", "text": "Manchester"}, {"id": "bir", "text": "Birmingham"}],
"sct": [{"id": "edi", "text": "Edinburgh"}, {"id": "gla", "text": "Glasgow"}],
"wls": [{"id": "car", "text": "Cardiff"}, {"id": "swa", "text": "Swansea"}],
"nir": [{"id": "bel", "text": "Belfast"}, {"id": "der", "text": "Derry"}]
}'
>
</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 (
<!-- Country -->
<label>Country</label>
<select
data-dot-select
data-chain-group="location"
data-chained-index="0"
data-placeholder="Select a country..."
>
<option value="">Select a country...</option>
<option value="us">United States</option>
<option value="ca">Canada</option>
<option value="uk">United Kingdom</option>
</select>
<!-- State / Province -->
<label>State / Province</label>
<select
data-dot-select
data-chain-group="location"
data-chained-index="1"
data-chained-disabled-on-empty="true"
data-chained-clear-on-parent-change="true"
data-placeholder="Select a state..."
data-chained-child-data='{
"us": [
{"id": "ca", "text": "California"},
{"id": "ny", "text": "New York"},
{"id": "tx", "text": "Texas"},
{"id": "fl", "text": "Florida"}
],
"ca": [
{"id": "on", "text": "Ontario"},
{"id": "bc", "text": "British Columbia"},
{"id": "qc", "text": "Quebec"},
{"id": "ab", "text": "Alberta"}
],
"uk": [
{"id": "eng", "text": "England"},
{"id": "sct", "text": "Scotland"},
{"id": "wls", "text": "Wales"},
{"id": "nir", "text": "Northern Ireland"}
]
}'
>
</select>
<!-- City -->
<label>City</label>
<select
data-dot-select
data-chain-group="location"
data-chained-index="2"
data-chained-disabled-on-empty="true"
data-chained-clear-on-parent-change="true"
data-placeholder="Select a city..."
data-chained-child-data='{
"ca": [{"id": "la", "text": "Los Angeles"}, {"id": "sf", "text": "San Francisco"}, {"id": "sd", "text": "San Diego"}],
"ny": [{"id": "nyc", "text": "New York City"}, {"id": "buf", "text": "Buffalo"}, {"id": "alb", "text": "Albany"}],
"tx": [{"id": "hou", "text": "Houston"}, {"id": "dal", "text": "Dallas"}, {"id": "aus", "text": "Austin"}],
"fl": [{"id": "mia", "text": "Miami"}, {"id": "orl", "text": "Orlando"}, {"id": "tam", "text": "Tampa"}],
"on": [{"id": "tor", "text": "Toronto"}, {"id": "ott", "text": "Ottawa"}, {"id": "ham", "text": "Hamilton"}],
"bc": [{"id": "van", "text": "Vancouver"}, {"id": "vic", "text": "Victoria"}],
"qc": [{"id": "mtl", "text": "Montreal"}, {"id": "qcc", "text": "Quebec City"}],
"ab": [{"id": "cal", "text": "Calgary"}, {"id": "edm", "text": "Edmonton"}],
"eng": [{"id": "lon", "text": "London"}, {"id": "man", "text": "Manchester"}, {"id": "bir", "text": "Birmingham"}],
"sct": [{"id": "edi", "text": "Edinburgh"}, {"id": "gla", "text": "Glasgow"}],
"wls": [{"id": "car", "text": "Cardiff"}, {"id": "swa", "text": "Swansea"}],
"nir": [{"id": "bel", "text": "Belfast"}, {"id": "der", "text": "Derry"}]
}'
>
</select>
)
}<template>
<!-- Country -->
<label>Country</label>
<select
data-dot-select
data-chain-group="location"
data-chained-index="0"
data-placeholder="Select a country..."
>
<option value="">Select a country...</option>
<option value="us">United States</option>
<option value="ca">Canada</option>
<option value="uk">United Kingdom</option>
</select>
<!-- State / Province -->
<label>State / Province</label>
<select
data-dot-select
data-chain-group="location"
data-chained-index="1"
data-chained-disabled-on-empty="true"
data-chained-clear-on-parent-change="true"
data-placeholder="Select a state..."
data-chained-child-data='{
"us": [
{"id": "ca", "text": "California"},
{"id": "ny", "text": "New York"},
{"id": "tx", "text": "Texas"},
{"id": "fl", "text": "Florida"}
],
"ca": [
{"id": "on", "text": "Ontario"},
{"id": "bc", "text": "British Columbia"},
{"id": "qc", "text": "Quebec"},
{"id": "ab", "text": "Alberta"}
],
"uk": [
{"id": "eng", "text": "England"},
{"id": "sct", "text": "Scotland"},
{"id": "wls", "text": "Wales"},
{"id": "nir", "text": "Northern Ireland"}
]
}'
>
</select>
<!-- City -->
<label>City</label>
<select
data-dot-select
data-chain-group="location"
data-chained-index="2"
data-chained-disabled-on-empty="true"
data-chained-clear-on-parent-change="true"
data-placeholder="Select a city..."
data-chained-child-data='{
"ca": [{"id": "la", "text": "Los Angeles"}, {"id": "sf", "text": "San Francisco"}, {"id": "sd", "text": "San Diego"}],
"ny": [{"id": "nyc", "text": "New York City"}, {"id": "buf", "text": "Buffalo"}, {"id": "alb", "text": "Albany"}],
"tx": [{"id": "hou", "text": "Houston"}, {"id": "dal", "text": "Dallas"}, {"id": "aus", "text": "Austin"}],
"fl": [{"id": "mia", "text": "Miami"}, {"id": "orl", "text": "Orlando"}, {"id": "tam", "text": "Tampa"}],
"on": [{"id": "tor", "text": "Toronto"}, {"id": "ott", "text": "Ottawa"}, {"id": "ham", "text": "Hamilton"}],
"bc": [{"id": "van", "text": "Vancouver"}, {"id": "vic", "text": "Victoria"}],
"qc": [{"id": "mtl", "text": "Montreal"}, {"id": "qcc", "text": "Quebec City"}],
"ab": [{"id": "cal", "text": "Calgary"}, {"id": "edm", "text": "Edmonton"}],
"eng": [{"id": "lon", "text": "London"}, {"id": "man", "text": "Manchester"}, {"id": "bir", "text": "Birmingham"}],
"sct": [{"id": "edi", "text": "Edinburgh"}, {"id": "gla", "text": "Glasgow"}],
"wls": [{"id": "car", "text": "Cardiff"}, {"id": "swa", "text": "Swansea"}],
"nir": [{"id": "bel", "text": "Belfast"}, {"id": "der", "text": "Derry"}]
}'
>
</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>AJAX Chain
A three-level chain that loads options from API endpoints:
<!-- Country -->
<label>Country</label>
<select
data-dot-select
data-chain-group="address"
data-chained-index="0"
data-searchable="true"
data-ajax-url="/api/countries?q={@term}"
data-placeholder="Search countries..."
data-allow-clear="true"
>
</select>
<!-- State -->
<label>State / Region</label>
<select
data-dot-select
data-chain-group="address"
data-chained-index="1"
data-searchable="true"
data-chained-child-ajax-data="/api/states?country={@val}&q={@term}"
data-chained-disabled-on-empty="true"
data-chained-clear-on-parent-change="true"
data-placeholder="Search states..."
>
</select>
<!-- City -->
<label>City</label>
<select
data-dot-select
data-chain-group="address"
data-chained-index="2"
data-searchable="true"
data-chained-child-ajax-data="/api/cities?state={@val}&q={@term}"
data-chained-disabled-on-empty="true"
data-chained-clear-on-parent-change="true"
data-placeholder="Search cities..."
>
</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 (
<!-- Country -->
<label>Country</label>
<select
data-dot-select
data-chain-group="address"
data-chained-index="0"
data-searchable="true"
data-ajax-url="/api/countries?q={@term}"
data-placeholder="Search countries..."
data-allow-clear="true"
>
</select>
<!-- State -->
<label>State / Region</label>
<select
data-dot-select
data-chain-group="address"
data-chained-index="1"
data-searchable="true"
data-chained-child-ajax-data="/api/states?country={@val}&q={@term}"
data-chained-disabled-on-empty="true"
data-chained-clear-on-parent-change="true"
data-placeholder="Search states..."
>
</select>
<!-- City -->
<label>City</label>
<select
data-dot-select
data-chain-group="address"
data-chained-index="2"
data-searchable="true"
data-chained-child-ajax-data="/api/cities?state={@val}&q={@term}"
data-chained-disabled-on-empty="true"
data-chained-clear-on-parent-change="true"
data-placeholder="Search cities..."
>
</select>
)
}<template>
<!-- Country -->
<label>Country</label>
<select
data-dot-select
data-chain-group="address"
data-chained-index="0"
data-searchable="true"
data-ajax-url="/api/countries?q={@term}"
data-placeholder="Search countries..."
data-allow-clear="true"
>
</select>
<!-- State -->
<label>State / Region</label>
<select
data-dot-select
data-chain-group="address"
data-chained-index="1"
data-searchable="true"
data-chained-child-ajax-data="/api/states?country={@val}&q={@term}"
data-chained-disabled-on-empty="true"
data-chained-clear-on-parent-change="true"
data-placeholder="Search states..."
>
</select>
<!-- City -->
<label>City</label>
<select
data-dot-select
data-chain-group="address"
data-chained-index="2"
data-searchable="true"
data-chained-child-ajax-data="/api/cities?state={@val}&q={@term}"
data-chained-disabled-on-empty="true"
data-chained-clear-on-parent-change="true"
data-placeholder="Search cities..."
>
</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>Two-Level Chain: Category and Subcategory
A simpler two-level chain:
<label>Category</label>
<select
data-dot-select
data-chain-group="category"
data-chained-index="0"
data-placeholder="Select a category..."
>
<option value="">Select a category...</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="books">Books</option>
</select>
<label>Subcategory</label>
<select
data-dot-select
data-chain-group="category"
data-chained-index="1"
data-chained-disabled-on-empty="true"
data-placeholder="Select a subcategory..."
data-chained-child-data='{
"electronics": [
{"id": "phones", "text": "Phones"},
{"id": "laptops", "text": "Laptops"},
{"id": "tablets", "text": "Tablets"},
{"id": "accessories", "text": "Accessories"}
],
"clothing": [
{"id": "mens", "text": "Men's"},
{"id": "womens", "text": "Women's"},
{"id": "kids", "text": "Kids"},
{"id": "shoes", "text": "Shoes"}
],
"books": [
{"id": "fiction", "text": "Fiction"},
{"id": "nonfiction", "text": "Non-Fiction"},
{"id": "technical", "text": "Technical"},
{"id": "children", "text": "Children's"}
]
}'
>
</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 (
<label>Category</label>
<select
data-dot-select
data-chain-group="category"
data-chained-index="0"
data-placeholder="Select a category..."
>
<option value="">Select a category...</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="books">Books</option>
</select>
<label>Subcategory</label>
<select
data-dot-select
data-chain-group="category"
data-chained-index="1"
data-chained-disabled-on-empty="true"
data-placeholder="Select a subcategory..."
data-chained-child-data='{
"electronics": [
{"id": "phones", "text": "Phones"},
{"id": "laptops", "text": "Laptops"},
{"id": "tablets", "text": "Tablets"},
{"id": "accessories", "text": "Accessories"}
],
"clothing": [
{"id": "mens", "text": "Men's"},
{"id": "womens", "text": "Women's"},
{"id": "kids", "text": "Kids"},
{"id": "shoes", "text": "Shoes"}
],
"books": [
{"id": "fiction", "text": "Fiction"},
{"id": "nonfiction", "text": "Non-Fiction"},
{"id": "technical", "text": "Technical"},
{"id": "children", "text": "Children's"}
]
}'
>
</select>
)
}<template>
<label>Category</label>
<select
data-dot-select
data-chain-group="category"
data-chained-index="0"
data-placeholder="Select a category..."
>
<option value="">Select a category...</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="books">Books</option>
</select>
<label>Subcategory</label>
<select
data-dot-select
data-chain-group="category"
data-chained-index="1"
data-chained-disabled-on-empty="true"
data-placeholder="Select a subcategory..."
data-chained-child-data='{
"electronics": [
{"id": "phones", "text": "Phones"},
{"id": "laptops", "text": "Laptops"},
{"id": "tablets", "text": "Tablets"},
{"id": "accessories", "text": "Accessories"}
],
"clothing": [
{"id": "mens", "text": "Men's"},
{"id": "womens", "text": "Women's"},
{"id": "kids", "text": "Kids"},
{"id": "shoes", "text": "Shoes"}
],
"books": [
{"id": "fiction", "text": "Fiction"},
{"id": "nonfiction", "text": "Non-Fiction"},
{"id": "technical", "text": "Technical"},
{"id": "children", "text": "Children's"}
]
}'
>
</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>Chain with Pre-Selected Values
Pre-populate a chain for editing an existing record:
<label>Country</label>
<select
data-dot-select
data-chain-group="edit-location"
data-chained-index="0"
data-searchable="true"
data-ajax-url="/api/countries?q={@term}"
data-ajax-resolve-url="/api/countries/resolve?ids={@selected}"
data-selected="us"
>
</select>
<label>State</label>
<select
data-dot-select
data-chain-group="edit-location"
data-chained-index="1"
data-searchable="true"
data-chained-child-ajax-data="/api/states?country={@val}&q={@term}"
data-ajax-resolve-url="/api/states/resolve?ids={@selected}"
data-selected="ca"
data-chained-disabled-on-empty="true"
>
</select>
<label>City</label>
<select
data-dot-select
data-chain-group="edit-location"
data-chained-index="2"
data-searchable="true"
data-chained-child-ajax-data="/api/cities?state={@val}&q={@term}"
data-ajax-resolve-url="/api/cities/resolve?ids={@selected}"
data-selected="sf"
data-chained-disabled-on-empty="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 (
<label>Country</label>
<select
data-dot-select
data-chain-group="edit-location"
data-chained-index="0"
data-searchable="true"
data-ajax-url="/api/countries?q={@term}"
data-ajax-resolve-url="/api/countries/resolve?ids={@selected}"
data-selected="us"
>
</select>
<label>State</label>
<select
data-dot-select
data-chain-group="edit-location"
data-chained-index="1"
data-searchable="true"
data-chained-child-ajax-data="/api/states?country={@val}&q={@term}"
data-ajax-resolve-url="/api/states/resolve?ids={@selected}"
data-selected="ca"
data-chained-disabled-on-empty="true"
>
</select>
<label>City</label>
<select
data-dot-select
data-chain-group="edit-location"
data-chained-index="2"
data-searchable="true"
data-chained-child-ajax-data="/api/cities?state={@val}&q={@term}"
data-ajax-resolve-url="/api/cities/resolve?ids={@selected}"
data-selected="sf"
data-chained-disabled-on-empty="true"
>
</select>
)
}<template>
<label>Country</label>
<select
data-dot-select
data-chain-group="edit-location"
data-chained-index="0"
data-searchable="true"
data-ajax-url="/api/countries?q={@term}"
data-ajax-resolve-url="/api/countries/resolve?ids={@selected}"
data-selected="us"
>
</select>
<label>State</label>
<select
data-dot-select
data-chain-group="edit-location"
data-chained-index="1"
data-searchable="true"
data-chained-child-ajax-data="/api/states?country={@val}&q={@term}"
data-ajax-resolve-url="/api/states/resolve?ids={@selected}"
data-selected="ca"
data-chained-disabled-on-empty="true"
>
</select>
<label>City</label>
<select
data-dot-select
data-chain-group="edit-location"
data-chained-index="2"
data-searchable="true"
data-chained-child-ajax-data="/api/cities?state={@val}&q={@term}"
data-ajax-resolve-url="/api/cities/resolve?ids={@selected}"
data-selected="sf"
data-chained-disabled-on-empty="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>Listening for Chain Events
html
<script>
const chain = DotSelect.chain('location');
chain.onChange((index, value, instance) => {
console.log(`Level ${index} changed to "${value}"`);
});
chain.whenReady(() => {
console.log('All levels ready. Values:', chain.getValues());
});
</script>