KQ-1667 · ADDRESS/CASCADE

Address Cascade

An address form under a search line: the search is a combobox that looks addresses up as you type, shows a quiet spinner only when a lookup is slow and always ends with Enter it manually. Choosing a suggestion closes the list on the exit ease and fills the fields one after another from top to bottom, staggerSpeed apart, each value sliding down into its field on springs.snap while an accent wash fades behind it and a check pops on snap and goes. Arrows move through the list, Enter picks, Escape closes then clears, and a failed lookup falls back to manual entry with what was typed in the first line.

KQ-1667 · ADDRESS/CASCADE

Delivery address

Search once; the fields fill themselves.

Can’t find it?

Address

We only ship within Northmere.

delivery · type a street or postcode

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/address-cascade

Props

fields
CascadeField[]
default defaultCascadeFields
The fields under the search in reading order: { id, label, autoComplete?, span?: "full" | "half", optional?, placeholder? }.
suggestions
CascadeSuggestion[]
default defaultCascadeSuggestions
The addresses the built-in lookup searches: { id, label, detail, values } with a value per field id.
onSuggest
(query: string) => CascadeSuggestion[] | Promise<CascadeSuggestion[]>
default —
Looks addresses up for a query; a promise shows the spinner once slow, a rejection falls back to manual entry. Defaults to filterCascadeSuggestions over suggestions.
value / defaultValue
Record<string, string>
default — / {}
Field values by field id, controlled or initial.
onValueChange
(values: Record<string, string>) => void
default —
Fires with every value after an edit, a pick or a manual fallback.
onChange
(fieldId: string, value: string, values: Record<string, string>) => void
default —
Fires for each field that changed, with its new value and every value.
onPick
(suggestion: CascadeSuggestion) => void
default —
A suggestion was chosen from the list.
onSubmit
(values: Record<string, string>) => void | Promise<unknown>
default —
The form was submitted with every required field filled; a promise shows Saving…, a rejection says Not saved.
lookupDelay
number
default 0
Pretend latency for the built-in lookup, ms.
spinnerDelay
number
default 250
A lookup slower than this shows the spinner, ms; faster ones never flash it.
minQuery
number
default 2
Characters typed before a lookup runs.
fieldStyle
"boxed" | "line" | "filled"
default "boxed"
Field look: bordered boxes, an underline, or tinted wells.
columns
number
default 2
Columns at wide widths, 1 to 3; under about 30rem the form always takes one.
staggerSpeed
number
default 70
Time between one field filling and the next in the cascade, ms.
accent
string
default "var(--accent-bright)"
The landing wash, the check, the spinner and Save: any CSS colour.
title
string
default "Delivery address"
The heading and the form's accessible name.
submitLabel
string
default "Save address"
The submit button's words.
maxHeight
number
default 560
Tallest the form grows before it scrolls inside, px.
disabled
boolean
default false
Fields and search are read-only and Save does nothing; the form dims.
className
string
default —
Classes for the outer form.