Components / Command

Command

Fast, composable command menu: the cmdk pattern in pure C#, with no JS dependency. A bordered surface holds a search input that filters items by a case-insensitive Contains match, grouped, with shortcuts, disabled rows, and an empty state. The input keeps focus while a virtual highlight roves the results via aria-activedescendant. This preview is the real component running in WebAssembly.

Examples

Start typing to filter. Groups hide when none of their items match, the empty state shows when nothing matches, and the disabled Calculator row is skipped by both the keyboard and the mouse.

Suggestions
Calendar
Search Emoji
Calculator
Settings
Profile ⌘P
Billing ⌘B
Settings ⌘S

Click the input, then use ↑ ↓ to move, Home / End to jump, Enter to select, Esc to clear. Calculator is disabled: navigation skips it and it ignores clicks.

Selected: none

razor
<ZitsCommand @bind-Query="_query" class="w-full max-w-[450px]">
    <ZitsCommandInput Placeholder="Type a command or search..." />
    <ZitsCommandList>
        <ZitsCommandEmpty>No results found.</ZitsCommandEmpty>
        <ZitsCommandGroup Heading="Suggestions">
            <ZitsCommandItem Value="Calendar" OnSelect="OnSelect"><span>Calendar</span></ZitsCommandItem>
            <ZitsCommandItem Value="Search Emoji" OnSelect="OnSelect"><span>Search Emoji</span></ZitsCommandItem>
            <ZitsCommandItem Value="Calculator" Disabled OnSelect="OnSelect"><span>Calculator</span></ZitsCommandItem>
        </ZitsCommandGroup>
        <ZitsCommandSeparator />
        <ZitsCommandGroup Heading="Settings">
            <ZitsCommandItem Value="Profile" OnSelect="OnSelect">
                <span>Profile</span><ZitsCommandShortcut>⌘P</ZitsCommandShortcut>
            </ZitsCommandItem>
            <ZitsCommandItem Value="Billing" OnSelect="OnSelect">
                <span>Billing</span><ZitsCommandShortcut>⌘B</ZitsCommandShortcut>
            </ZitsCommandItem>
            <ZitsCommandItem Value="Settings" OnSelect="OnSelect">
                <span>Settings</span><ZitsCommandShortcut>⌘S</ZitsCommandShortcut>
            </ZitsCommandItem>
        </ZitsCommandGroup>
    </ZitsCommandList>
</ZitsCommand>

@code {
    private string _query = string.Empty;
    private void OnSelect(string value) { /* handle the selection */ }
}

Keyboard

The input never loses DOM focus. It is a role="combobox" whose aria-activedescendant points at a virtual active item rather than moving real focus. The active row carries data-active, data-highlighted and aria-selected="true", and is scrolled into view. Navigation only ever lands on rows that match the query and are not disabled. Mouse hover sets the active row too.

KeyAction
Move the highlight to the next item; wraps to the first.
Move the highlight to the previous item; wraps to the last.
HomeJump to the first matching item.
EndJump to the last matching item.
EnterSelect the active item; invokes its OnSelect with the item's Value.
EscClear the query. When the query is already empty it no-ops, so a host dialog can handle the key and close.

Typing reruns the filter and resets the highlight to the first match (cmdk behaviour), so Enter right after a search always selects the top result.

Anatomy

Compose the parts inside ZitsCommand. Each ZitsCommandItem filters against its Value; a ZitsCommandShortcut renders the trailing hint and Disabled dims a row out of the rotation.

Command.razor razor
<ZitsCommand @bind-Query="_query">
    <ZitsCommandInput Placeholder="Search..." />
    <ZitsCommandList>
        <ZitsCommandEmpty>No results found.</ZitsCommandEmpty>
        <ZitsCommandGroup Heading="Group">
            <ZitsCommandItem Value="Item" OnSelect="OnSelect">
                <span>Item</span>
                <ZitsCommandShortcut>⌘I</ZitsCommandShortcut>
            </ZitsCommandItem>
            <ZitsCommandItem Value="Off" Disabled> ... </ZitsCommandItem>
        </ZitsCommandGroup>
        <ZitsCommandSeparator />
    </ZitsCommandList>
</ZitsCommand>

Installation

Terminal bash
navius add command

API reference

ZitsCommand

The root. Owns the query and the virtual active item; cascades both to the parts below.

Prop Type Default
Query string ""
QueryChanged EventCallback<string> -
ChildContent RenderFragment? -

ZitsCommandInput

The search field: role="combobox", drives the query, owns the keyboard model. Extra attributes are splatted onto the <input>.

Prop Type Default
Placeholder string? -

ZitsCommandGroup

A labelled section. The whole group (heading included) hides when none of its items match.

Prop Type Default
Heading string? -
ChildContent RenderFragment? -

ZitsCommandItem

A selectable row. ZitsCommandList, ZitsCommandEmpty, ZitsCommandSeparator and ZitsCommandShortcut take only ChildContent plus splatted attributes.

Prop Type Default
Value string ""
Selected bool false
Disabled bool false
OnSelect EventCallback<string> -
ChildContent RenderFragment? -