Rask
Rask
v0.23.1-alpha.0.494

Components

Autocomplete

An input that suggests what to type and writes the picked suggestion into itself. What it holds is the text, so anything may be typed; to show a name and store an id, use a select's combobox instead.

Drawn and behaving as Flux UI's autocomplete does, measured against its live docs.

Autocomplete

Type "ne": the list narrows to the states that hold it, and Enter writes the lit one into the input.

AutocompleteExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class AutocompleteExample : Component
{
    private static readonly string[] States =
    [
        "Alabama", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
        "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
        "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico",
        "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
        "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia",
        "Wisconsin", "Wyoming",
    ];

    private string _state = "";

    protected override Component? Render() =>
        Div.Class("max-w-sm space-y-3")[
            Ui.Autocomplete.Value(_state).OnChange(text => { _state = text; }).Label("State of residence").Id("ui-autocomplete-state")[
                States.Select(state => Ui.AutocompleteItem.Key(state)[state])
            ],
            Ui.Text.Data("testid", "ui-autocomplete-value")[_state.Length == 0 ? "Nothing typed." : $"State: {_state}."]
        ];
}
Live result
Alabama
Arkansas
California
Colorado
Connecticut
Delaware
Florida
Georgia
Hawaii
Idaho
Illinois
Indiana
Iowa
Kansas
Kentucky
Louisiana
Maine
Maryland
Massachusetts
Michigan
Minnesota
Mississippi
Missouri
Montana
Nebraska
Nevada
New Hampshire
New Jersey
New Mexico
New York
North Carolina
North Dakota
Ohio
Oklahoma
Oregon
Pennsylvania
Rhode Island
South Carolina
South Dakota
Tennessee
Texas
Utah
Vermont
Virginia
Washington
West Virginia
Wisconsin
Wyoming

Nothing typed.

Suggestions from the server

Debounce hands the page what was typed once typing has paused, and the page answers with the items: one query for a word, not one for a letter.

AutocompleteSearchExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class AutocompleteSearchExample : Component
{
    // What a table would hold: more rows than a list shows, so the page answers a search with the first few.
    private static readonly string[] Cities =
    [
        "Amsterdam", "Athens", "Berlin", "Bern", "Brussels", "Budapest", "Copenhagen", "Dublin", "Helsinki", "Lisbon",
        "Ljubljana", "Madrid", "Oslo", "Paris", "Prague", "Riga", "Rome", "Stockholm", "Vienna", "Warsaw",
    ];

    private string _city = "";
    private string[] _found = [.. Cities.Take(6)];
    private int _searches;

    protected override Component? Render() =>
        Div.Class("max-w-sm space-y-3")[
            Ui.Autocomplete.Value(_city).OnChange(Search).Debounce(250.Milliseconds).Label("City").Id("ui-autocomplete-city")[
                _found.Select(city => Ui.AutocompleteItem.Key(city)[city])
            ],
            Ui.Text.Data("testid", "ui-autocomplete-city-state")[
                $"City: {(_city.Length == 0 ? "none" : _city)}. Searches: {_searches}."
            ]
        ];

    private void Search(string text)
    {
        _city = text;
        _searches++;
        _found = [.. Cities.Where(name => name.Contains(text, StringComparison.CurrentCultureIgnoreCase)).Take(6)];
    }
}
Live result
Amsterdam
Athens
Berlin
Bern
Brussels
Budapest

City: none. Searches: 0.

Behaviour

It holds the text

An item has no value of its own, and what is typed need not be an item. The text reaches the page as an input's does: a bound member with the next action (.Live(): as it is typed), and OnChange when an item is picked, when Escape empties the input, and when what was typed is left.

It takes the input's own steps, which is what Flux documents for it: Type, Size, Variant, Icon, Kbd, Clearable(), Copyable(), Mask and the rest, and ContainerClass for the open list (a height, such as max-h-80).

Suggestions from the server

Debounce(250.Milliseconds) hands the page what was typed once typing has paused as well (Flux's wire:model.live.debounce.250ms), and the page answers it with the items. The autocomplete has no search callback apart from its value: what is typed is what it holds, so the pause is when the value arrives.

The list still narrows at every keystroke, since Flux's autocomplete has no filter to turn off, and only the page waits. An item pressed during the pause is the text, and what was typed before it is never handed over. A bound autocomplete writes its member at the pause: Debounce is a way of being Live(), so AfterBind is where the search goes.

The keyboard

Recorded on fluxui.dev and matched. The cursor, the filter and the pick are the browser's, and nothing is sent to the page until the input's text is.

Key
What happens
A click, ArrowDown, ArrowUpOpen the list; the cursor starts on the item last picked, else the first.
TypingOpens the list on the items that hold the text anywhere, whatever the case or the accents. When nothing matches, nothing is drawn.
ArrowDown, ArrowUpMove the cursor and stop at either end. Home and End are the text's own.
EnterWrites the active item into the input and closes. With no active item it does nothing.
EscapeCloses the list and empties the input, open or not.
Tab, a click elsewhereClose, and keep whatever was typed.
The pointerLights the row it enters, which goes dark when the pointer leaves the list; a click picks it and the focus stays in the input.

No script of the kit's

The list is a native popover placed by CSS anchor positioning, and the cursor, the filter, the open state and the pick are the runtime's (data-rask-list). The page behind the open list is locked (data-rask-lock).

The input is role="combobox" with aria-autocomplete="list", aria-haspopup="listbox", aria-expanded, aria-controls and, while open, aria-activedescendant. The list is role="listbox" and, as Flux writes it, aria-multiselectable="true"; the item last picked stays aria-selected whatever is typed afterwards.

Reference

Ui.Autocomplete

flux:autocomplete

A text input that suggests what to type. Its items are its children.

Step
Takes
What it does
.Bind(…)() => a stringThe member it reads and writes: () => m.State. Or Value with OnChange.
.Value(…)stringThe text, for a page that holds it itself.
.OnChange(…)a handler given the new valueRuns with the text when it is picked, cleared, or typed and left, and with Debounce once typing has paused.
.AfterBind(…)a handler given the new valueRuns after Bind has written the model.
.Validate(…)a validatorA rule the text is checked by when it is written.
.Live()boolWrites the model as soon as an item is picked, not with the next action.
.Debounce(…)a TimeSpan: 250.MillisecondsHands the page what was typed once typing has paused this long: suggestions from a database.
.Type(…)
InputType
Text
Search
Tel
Url
Email
Password
Number
Checkbox
Radio
File
Range
Color
Date
DatetimeLocal
Time
Week
Month
Hidden
Button
Submit
Reset
Image

Each is a step of its own too, unless an HTML tag has its name.

The input's type. Text when unset.
.Label(…)stringDraws a field around it, with this label and the error.
.Description(…)stringHelp text between the label and the input.
.Placeholder(…)stringShown while it is empty.
.Size(…)
Ui.AutocompleteSize
Base
Sm
Xs

Each is a step of its own too, unless an HTML tag has its name.

How tall it is. 40px when unset.
.Variant(…)
Ui.AutocompleteVariant
Outline
Filled

Each is a step of its own too, unless an HTML tag has its name.

Outlined, or filled with no border. Outlined when unset.
.Disabled()boolAn input that cannot be typed into or opened.
.ReadOnly()boolShows its text and takes none.
.Invalid()boolError styling the form did not ask for.
.Multiple()boolFor a file input: several files.
.Mask(…)stringA pattern the text is laid into: 99/99/9999.
.Icon(…)Ui.IconName, or a componentAn icon, or content, at the start of the input.
.IconTrailing(…)Ui.IconName, or a componentAn icon, or content, at the end of the input.
.Kbd(…)stringA keyboard shortcut shown at the end of the input.
.Clearable()boolA button that empties the input, while it has text.
.Copyable()boolA button that copies what it holds.
.Viewable()boolFor a password input: a button that shows what was typed.
.As(…)
Ui.AutocompleteAs
Input
Button

Each is a step of its own too, unless an HTML tag has its name.

What it is drawn as. The input when unset.
.ContainerClass(…)stringClasses for the open list: a height, such as max-h-80.
.InputClass(…)stringClasses for the <input> itself rather than the box around it.
.ShowValidation()boolFalse leaves the member's message to a Ui.Error placed elsewhere.

Ui.AutocompleteItem

flux:autocomplete.item

One suggestion. Its children are its words.

Step
Takes
What it does
.Disabled()boolShown but not pickable.
Confirm