Command
Overview
Section titled “Overview”Command implements the cmdk pattern from scratch: a bordered surface holding a search
input, a scrollable list, and items that filter against the query (case-insensitive
Contains by default). Items and groups register with the root via a cascading context so
a group hides when none of its items match and ZitsCommandEmpty shows when nothing does.
It composes no Navius primitive; all filtering, active-item tracking, and keyboard handling
are the component’s own C#.
Install
Section titled “Install”navius add command --to ./src/MyApp --namespace MyApp.Ui@using Zits.Ui.Components
<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">Calendar</ZitsCommandItem> <ZitsCommandItem Value="Calculator" Disabled OnSelect="OnSelect">Calculator</ZitsCommandItem> </ZitsCommandGroup> <ZitsCommandSeparator /> <ZitsCommandGroup Heading="Settings"> <ZitsCommandItem Value="Profile" OnSelect="OnSelect"> Profile <ZitsCommandShortcut>⌘P</ZitsCommandShortcut> </ZitsCommandItem> </ZitsCommandGroup> </ZitsCommandList></ZitsCommand>
@code { private string _query = string.Empty; private void OnSelect(string value) { }}Parts and props
Section titled “Parts and props”ZitsCommand (root)
| Prop | Type | Default | Description |
|---|---|---|---|
Query / QueryChanged |
string |
"" |
The search query. Bind with @bind-Query. |
ZitsCommandInput
| Prop | Type | Default | Description |
|---|---|---|---|
Placeholder |
string? |
null |
Placeholder text for the search field. |
ZitsCommandList
| Prop | Type | Default | Description |
|---|---|---|---|
AriaLabel |
string |
"Suggestions" |
Accessible name for the listbox. |
ZitsCommandGroup
| Prop | Type | Default | Description |
|---|---|---|---|
Heading |
string? |
null |
Section heading; the whole group (heading included) hides when none of its items match. |
ZitsCommandItem
| Prop | Type | Default | Description |
|---|---|---|---|
Value |
string |
"" |
Text matched against the query, and the value passed to OnSelect. |
Selected |
bool |
false |
Marks the row as selected independent of keyboard/mouse activity. |
Disabled |
bool |
false |
Excludes the row from navigation, filtering match, and click. |
OnSelect |
EventCallback<string> |
Fired on click, or Enter while the row is the active row. |
ZitsCommandEmpty, ZitsCommandSeparator, ZitsCommandShortcut take only
ChildContent/Attributes; they render conditionally (Empty) or are purely presentational
(Separator, Shortcut).
Styling surface
Section titled “Styling surface”Every part accepts class via Attributes, merged with its base class through
Cn.Merge.
Data attribute hooks
Section titled “Data attribute hooks”| Part | Attribute | Description |
|---|---|---|
| Item | data-active / data-highlighted |
Present on the virtually-active row (keyboard highlight or hover). |
| Item | data-selected |
Present when Selected is set. |
| Item | data-disabled |
Present when Disabled is set; also drives pointer-events-none styling. |
Command wires its own ARIA mechanism: the input carries role="combobox",
aria-expanded="true", aria-controls pointing at the list’s id, and
aria-activedescendant pointing at the current active item’s id. The list is
role="listbox" with an accessible name from AriaLabel; groups are role="group" and
hide via the hidden attribute when empty; items are role="option" with
aria-selected. Keyboard handling lives on the input: ArrowDown/ArrowUp move the active
item (wrapping), Home/End jump to the ends, Enter invokes the active item’s OnSelect,
and Escape clears a non-empty query (a no-op otherwise, so a hosting dialog can still
close on Escape). Hovering a row also makes it active. The active row is scrolled into
view through the engine’s NaviusJsInterop.ScrollIntoViewByIdAsync (CSP-safe, no eval).