A cascader picks a path through nested options shown in columns. Each choice opens the next column, and the form submits the whole path.
Write a text field with the
cascader class, holding a named <input>, its
label and a ul.cascader-options of nested lists. Each
<li> holds a data-value, and its label is its own
text. AutoInit() starts every .cascader; the lists stay
hidden, and the columns are built from them. Mark a leaf
data-selected to start with its path.
<div class="field cascader">
<input id="place" name="place" type="text" required>
<label for="place">Place</label>
<ul class="cascader-options">
<li data-value="us">United States
<ul>
<li data-value="ca">California
<ul>
<li data-value="sf">San Francisco</li>
<li data-value="la">Los Angeles</li>
</ul>
</li>
</ul>
</li>
<li data-value="mx">Mexico</li>
</ul>
</div>
Keyboard
Enter, Space or ArrowDown opens the columns. ArrowDown and ArrowUp move within a
column, and Home and End go to its ends. ArrowRight or Enter on a branch opens the
next column, and ArrowLeft goes back to the option that opened it. Enter or Space
on a leaf commits the path. Escape and Tab close without committing and return
focus to the field. Under dir="rtl" the columns run right to left and
the arrow keys swap.
The submitted path
The field shows the path's labels, such as
United States / California / San Francisco, and fires
input and change when the path changes. The form gets
one entry per level under the input's name, in order, so
new FormData(form).getAll('place') returns
['us', 'ca', 'sf']. A form reset brings back the starting path.
With required, the form does not submit until a path is chosen. A
disabled field submits nothing.
Options and methods
i18n.required replaces the message a required field shows, from
script or from data-cascader-options on the
.cascader.
const place = Expressive.Cascader.getInstance(document.querySelector('.cascader'));
place.value; // ['us', 'ca', 'sf'], or [] before a path is chosen
place.open(); // opens the columns at the chosen path
place.close();
place.destroy(); // removes the columns and gives the input back its name