Form: cascading fields
SvForm dependent selects - a child list derives from the parent value via a function `options`, and `dependsOn` clears the child when the parent changes so a stale selection never lingers. Country -> State -> City.
A live, editable Svelte 5 component example from the SvGrid gallery (Layout). Read the SvGrid UI component docs for the full API.
About this example
Dependent selects in SvForm for Svelte 5: a child field's options is a function of the current values, so State lists only the states of the chosen Country and City only the cities of the chosen State, and dependsOn clears the child when its parent changes so a stale selection never lingers.
SvForm cascading (dependent) fields - a child list derives from the parent's value via a function options, and dependsOn clears the child when the parent changes so a stale selection never lingers. Country -> State -> City.
Imports, features and API used
Imports: @svgrid/grid
Frequently asked questions
How do I derive a field's options from another field?
Give the field options: (values) => list. SvForm calls it whenever values change, so the State select always reflects the current Country.
Why is dependsOn needed as well?
Without it a chosen state would stay selected after the country changed even though it is no longer in the list. dependsOn: ['country'] resets the child when the parent changes.
Does this work for more than two levels?
Yes. City depends on State which depends on Country here; each level declares its own dependsOn.
Related documentation
Related articles
- Avoiding Layout Thrash in Custom Grid Cells - Layout thrash from interleaved DOM reads and writes is the most common cause of scroll jank in grids with custom cells - here is how to find it and design your way out of it.
- Column Definitions in SvGrid - Fields, Accessors, and Formatting - A practical look at how ColumnDef controls field binding, value resolution, sort behavior, and custom cell rendering in SvGrid.
- Stable Row Identity in SvGrid (and why it matters) - How SvGrid tracks rows across mutations, why object reference stability is the key to correct selection and editing, and the exact patterns to use with live data feeds.
Source code (405-form-cascading.svelte)
<script lang="ts">
/**
* SvForm cascading (dependent) fields - a child list derives from the parent's
* value via a function `options`, and `dependsOn` clears the child when the
* parent changes so a stale selection never lingers. Country -> State -> City.
*/
import { SvForm, SvToaster, toast, type FormField } from '@svgrid/grid'
const countries = [
{ value: 'us', label: 'United States' },
{ value: 'ca', label: 'Canada' },
]
const states: Record<string, { value: string; label: string }[]> = {
us: [ { value: 'ca-s', label: 'California' }, { value: 'ny', label: 'New York' }, { value: 'tx', label: 'Texas' } ],
ca: [ { value: 'on', label: 'Ontario' }, { value: 'bc', label: 'British Columbia' }, { value: 'qc', label: 'Quebec' } ],
}
const cities: Record<string, { value: string; label: string }[]> = {
'ca-s': [ { value: 'la', label: 'Los Angeles' }, { value: 'sf', label: 'San Francisco' } ],
ny: [ { value: 'nyc', label: 'New York City' }, { value: 'buf', label: 'Buffalo' } ],
tx: [ { value: 'aus', label: 'Austin' }, { value: 'dal', label: 'Dallas' } ],
on: [ { value: 'tor', label: 'Toronto' }, { value: 'ott', label: 'Ottawa' } ],
bc: [ { value: 'van', label: 'Vancouver' }, { value: 'vic', label: 'Victoria' } ],
qc: [ { value: 'mtl', label: 'Montreal' }, { value: 'qcc', label: 'Quebec City' } ],
}
const fields: FormField[] = [
{ name: 'country', label: 'Country', type: 'select', options: countries, required: true, placeholder: 'Pick a country' },
{ name: 'state', label: 'State / Province', type: 'select', dependsOn: 'country', required: true, placeholder: 'Pick a state',
options: (v) => states[v.country] ?? [] },
{ name: 'city', label: 'City', type: 'select', dependsOn: 'state', required: true, placeholder: 'Pick a city',
options: (v) => cities[v.state] ?? [] },
]
function onSubmit(values: Record<string, unknown>) {
toast.success(`Selected ${values.city} (${values.state}, ${values.country})`)
}
</script>
<div class="wrap">
<h2>Cascading location</h2>
<p class="muted">Each list depends on the one above; changing a parent clears its children.</p>
<SvForm {fields} columns={1} submitLabel="Save location" {onSubmit} />
</div>
<SvToaster position="bottom-right" />
<style>
.wrap { padding: 22px; max-width: 420px; }
h2 { margin: 0; font-size: 19px; font-weight: 700; }
.muted { margin: 3px 0 16px; color: var(--sg-muted, #64748b); font-size: 13px; }
</style>More Layout examples
- Account & security settings console - A real SaaS settings surface composed from the UI kit: SvMenubar app bar, promise + Undo-action toasts on save, SvPopconfirm on destructive rows, SvHoverCard teammate previews, and frame input adornments (leading icons, prefix affixes, masked API key). Profile / Team / Security tabs over SvCard + SvStat.
- Invoice builder - An adornment-heavy money form: currency prefixes, % suffixes, masked tax IDs (frame adornments), line items with SvPopconfirm delete + Undo action toasts, live SvStat totals, an SvHoverCard tax hint, and a promise toast on Send. Pure UI-kit composition.
- Operations KPI dashboard - A KPI console: SvStat + SvSparkline tiles, an SvGauge SLA dial, SvHoverCard drill-down previews per service, an SvMenubar toolbar (View / Range / Actions) and a promise toast on Refresh. Pure UI-kit composition, no grid dependency.
- Form: rich field types - SvForm reaching the whole input suite from one schema - phone, country, mask, combobox, radio, slider, tags, datetime and file - plus per-field help text, a readonly field, column span, and a promise toast on submit.
- Layout & feedback primitives - The structural + status kit: SvStack / SvGroup / SvSimpleGrid layout primitives, SvCollapsible show/hide sections, SvSpinner + SvLoadingOverlay for async states, and SvResult for a full outcome page. All themed from the --sg-* tokens.