# Command

Dialog command palette with search, grouped items, and separators.

- Package: `@mielui/svelte`
- Component version: `1.3.0`
- Depends on Mielui components: _internal/utils, dialog, button
- Shared utilities: hugeicons-icon, utils.cn, utils.createContext, utils.travelingHighlight

## Install

~~~~sh
pnpm dlx @mielui/svelte add command
~~~~

## API

This reference is generated at build time from the component manifest, public `index.ts`, and documentation examples below. Changes to those source files are reflected here in the published Markdown. Standard Svelte and HTML attributes accepted by the exported prop types are supported.


### Content

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| surface | "solid" \| "glass" \| undefined | - | No | No | Surface treatment. Omit it to inherit `--mielui-surface` from the theme. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| class | string \| undefined | - | No | No | Classes added to the element. |
| allowClickOutside | boolean \| undefined | true | No | No | Closes when the pointer is pressed outside it. Set false to keep it open until it is dismissed another way. |



### Group

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[]> | - | Yes | No | Content rendered inside. |
| class | string \| undefined | - | No | No | Classes added to the element. |
| heading | string | - | Yes | No | Heading shown above the group. |



### Header

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| class | string \| undefined | - | No | No | Classes added to the element. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |



### Item

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| name | string \| undefined | - | No | No | Text the search matches. |
| value | string \| undefined | - | No | No | Identifier for the item when names repeat. |
| callback | (() => void) \| undefined | - | No | No | Called when the item is chosen. |
| disabled | boolean \| undefined | false | No | No | Prevents interaction and dims the control. |
| href | string \| undefined | - | No | No | Navigates to this address when the item is chosen. |
| onclick | (() => void) \| undefined | - | No | No | Called when it is clicked or activated. |
| class | string \| undefined | - | No | No | Classes added to the element. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |



### Results

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| class | string \| undefined | - | No | No | Classes added to the element. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| empty | Snippet<[]> \| undefined | - | No | No | Content shown when nothing matches. |



### Root

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| labels | CommandLabels \| undefined | - | No | No | Overrides the built-in text and accessible names. Every key is optional and English is the fallback. |
| open | boolean \| undefined | false | No | Yes | Whether it is open. Bind it to control the state from outside. |
| onOpenChange | ((open: boolean) => void) \| undefined | - | No | No | Called with the new state whenever it opens or closes. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |



### Search

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| threshold | number \| undefined | DEFAULT_COMMAND_SEARCH_THRESHOLD | No | No | How loosely typed text may match, from 0 for exact to 1 for anything. |
| icon | Snippet<[]> \| undefined | - | No | No | Replaces the search icon. |
| count | Snippet<[count: number]> \| undefined | - | No | No | Renders the result count. |
| announcement | Snippet<[message: string]> \| undefined | - | No | No | Renders the screen reader announcement. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Separator

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| class | string \| undefined | - | No | No | Classes added to the element. |



### Trigger

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| disabled | boolean \| undefined | - | No | No | Prevents activation. A disabled link loses its destination and is skipped by Tab. |
| variant | ButtonVariant \| undefined | - | No | No | Visual style. Choose it for what the action means, not for decoration. |
| size | "sm" \| "md" \| "lg" \| "icon" \| undefined | - | No | No | Control height. `icon` is a square button for a single icon. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| element | HTMLButtonElement \| HTMLAnchorElement \| undefined | - | No | No | Bindable reference to the rendered DOM element. Type is the union of the two possible element types -- narrow at the use site: |
| unstyled | boolean \| undefined | - | No | No | Skip the variant/size base classes and render with `class` alone. |
| status | ButtonStatus \| undefined | - | No | No | Controlled visual state. Loading remains focusable and refuses activation. |
| loading | boolean \| undefined | - | No | No | Convenience alias for `status="loading"`. |
| labels | ButtonLabels \| undefined | - | No | No | Overrides the built-in text and accessible names. Every key is optional and English is the fallback. |
| onclick | ((event: MouseEvent) => void) \| undefined | - | No | No | Called when the button is activated. Loading and disabled buttons do not call it. |
| onkeydown | ((event: KeyboardEvent) => void) \| undefined | - | No | No | Called on key down, before the button handles the key itself. |
| href | string \| undefined | - | No | No | Renders a link to this address instead of a button. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Public types

~~~~ts
import type { DefaultProps } from '@mielui/svelte/utils';
import type { Snippet } from 'svelte';
import type { HTMLInputAttributes } from 'svelte/elements';
import Root from './command.svelte';
import Content from './command-content.svelte';
import Group from './command-group.svelte';
import Header from './command-header.svelte';
import Item from './command-item.svelte';
import Results from './command-results.svelte';
import Search from './command-search.svelte';
import Separator from './command-separator.svelte';
import Trigger from './command-trigger.svelte';

export type CommandItem = {
    id: string;
    name: string;
    callback: (() => void) | undefined;
    ref: HTMLButtonElement | HTMLAnchorElement | undefined;
    disabled: boolean;
};

export type CommandLabels = {
    /** Accessible name of the palette dialog. */
    palette?: string;
    /** Placeholder of the search input. The `placeholder` prop on Search wins. */
    searchPlaceholder?: string;
    /** Accessible name of the search input. */
    search?: string;
    /** Accessible name of the results list. */
    results?: string;
    /** Text shown when nothing matches and Results has no `empty` snippet. */
    empty?: string;
    /** Screen reader announcement of how many commands match the search. */
    available?: (count: number) => string;
};

export type CommandProps = {
    /**
     * Overrides the built-in text and accessible names. Every key is optional and English is the
     * fallback.
     */
    labels?: CommandLabels;
    /** Whether it is open. Bind it to control the state from outside. */
    open?: boolean;
    /** Called with the new state whenever it opens or closes. */
    onOpenChange?: (open: boolean) => void;
    /** Content rendered inside. */
    children?: Snippet;
};

export type CommandItemProps = {
    /** Text the search matches. */
    name?: string;
    /** Identifier for the item when names repeat. */
    value?: string;
    /** Called when the item is chosen. */
    callback?: () => void;
    /** Prevents interaction and dims the control. */
    disabled?: boolean;
    /** Navigates to this address when the item is chosen. */
    href?: string;
    /** Called when it is clicked or activated. */
    onclick?: () => void;
} & DefaultProps;

export type CommandHeaderProps = DefaultProps;

export type CommandSearchProps = Omit<HTMLInputAttributes, 'children'> & {
    /** How loosely typed text may match, from 0 for exact to 1 for anything. */
    threshold?: number;
    /** Replaces the search icon. */
    icon?: Snippet;
    /** Renders the result count. */
    count?: Snippet<[count: number]>;
    /** Renders the screen reader announcement. */
    announcement?: Snippet<[message: string]>;
};

export type CommandResultsProps = DefaultProps & {
    /** Content shown when nothing matches. */
    empty?: Snippet;
};

export type CommandState = {
    id: string;
    items: CommandItem[];
    results: CommandItem[];
    searchContent: string;
    activeId: string | undefined;
    itemsVersion: number;
};

export { Content, Group, Header, Item, Results, Root, Search, Separator, Trigger };
~~~~

## Examples

### Controlled

~~~~svelte
<script lang="ts">
    import { Button } from '@mielui/svelte/components/button';
    import * as Command from '@mielui/svelte/components/command';

    let open = $state(false);
    let picked = $state('Nothing picked yet');
</script>

<div class="flex flex-col items-center gap-3">
    <Button
        variant="outline"
        onclick={() => {
            open = true;
        }}
    >
        Open the palette from a button
    </Button>
    <Command.Root bind:open labels={{ palette: 'Workspace commands' }}>
        <Command.Content allowClickOutside={false}>
            <Command.Search placeholder="Try typing invce" threshold={0.5} />
            <Command.Results>
                <Command.Group heading="Create">
                    <Command.Item
                        name="New invoice"
                        callback={() => {
                            picked = 'New invoice';
                        }}
                    >
                        New invoice
                    </Command.Item>
                    <Command.Item
                        name="New customer"
                        callback={() => {
                            picked = 'New customer';
                        }}
                    >
                        New customer
                    </Command.Item>
                </Command.Group>
            </Command.Results>
        </Command.Content>
    </Command.Root>
    <p class="text-sm text-foreground-muted">{picked}</p>
</div>
~~~~

### Glass

~~~~svelte
<script lang="ts">
    import {
        CircleDotIcon as CircleDot,
        InboxIcon as Inbox,
        MapsIcon as MapIcon,
        Search01Icon as Search
    } from '@hugeicons/core-free-icons';
    import * as Command from '@mielui/svelte/components/command';
    import HugeiconsIcon from '@mielui/svelte/hugeicons-icon';
</script>

<Command.Root>
    <Command.Trigger variant="outline">
        <HugeiconsIcon icon={Search} size={14} />
        Open glass palette
    </Command.Trigger>
    <Command.Content surface="glass">
        <Command.Search />
        <Command.Results>
            <Command.Group heading="Jump to">
                <Command.Item name="Inbox">
                    <HugeiconsIcon icon={Inbox} size={16} />
                    Inbox
                </Command.Item>
                <Command.Item name="My Issues">
                    <HugeiconsIcon icon={CircleDot} size={16} />
                    My Issues
                </Command.Item>
                <Command.Item name="Roadmap">
                    <HugeiconsIcon icon={MapIcon} size={16} />
                    Roadmap
                </Command.Item>
            </Command.Group>
        </Command.Results>
    </Command.Content>
</Command.Root>
~~~~

### Hero

~~~~svelte
<script lang="ts">
    import {
        CircleDotIcon as CircleDot,
        FolderAddIcon as FolderPlus,
        InboxIcon as Inbox,
        MapsIcon as MapIcon,
        Moon02Icon as Moon,
        Search01Icon as Search,
        Edit01Icon as SquarePen,
        UserGroupIcon as Users
    } from '@hugeicons/core-free-icons';
    import * as Command from '@mielui/svelte/components/command';
    import Kbd from '@mielui/svelte/components/kbd';
    import HugeiconsIcon from '@mielui/svelte/hugeicons-icon';

    let selected = $state('No command selected');
</script>

<div class="flex w-full flex-col items-center justify-center gap-4">
    <Command.Root>
        <Command.Trigger
            variant="outline"
            class="w-[16rem] max-w-full justify-between gap-2 px-3 py-2 text-foreground-muted"
        >
            <div class="flex min-w-0 items-center gap-2">
                <HugeiconsIcon icon={Search} size={16} />
                <span class="truncate">Search or jump to…</span>
            </div>
            <Kbd shortcut="cmd+K" class="shrink-0" />
        </Command.Trigger>
        <Command.Content>
            <Command.Header>
                <span>Command</span>
                <span class="ml-auto flex items-center gap-1.5">
                    <Kbd shortcut="esc" />
                    close
                </span>
            </Command.Header>
            <Command.Search placeholder="Type a command or search…" />
            <Command.Results>
                <Command.Group heading="Jump to">
                    <Command.Item
                        name="Inbox"
                        callback={() => {
                            selected = 'Inbox selected';
                        }}
                    >
                        <HugeiconsIcon icon={Inbox} size={16} />
                        Inbox
                    </Command.Item>
                    <Command.Item
                        name="My Issues"
                        callback={() => {
                            selected = 'My Issues selected';
                        }}
                    >
                        <HugeiconsIcon icon={CircleDot} size={16} />
                        My Issues
                    </Command.Item>
                    <Command.Item
                        name="Roadmap"
                        callback={() => {
                            selected = 'Roadmap selected';
                        }}
                    >
                        <HugeiconsIcon icon={MapIcon} size={16} />
                        Roadmap
                    </Command.Item>
                </Command.Group>
                <Command.Separator />
                <Command.Group heading="Create">
                    <Command.Item
                        name="New issue"
                        callback={() => {
                            selected = 'New issue selected';
                        }}
                    >
                        <HugeiconsIcon icon={SquarePen} size={16} />
                        <span class="flex-1">New issue</span>
                        <Kbd shortcut="C" />
                    </Command.Item>
                    <Command.Item
                        name="New project"
                        callback={() => {
                            selected = 'New project selected';
                        }}
                    >
                        <HugeiconsIcon icon={FolderPlus} size={16} />
                        New project
                    </Command.Item>
                </Command.Group>
                <Command.Separator />
                <Command.Group heading="Settings">
                    <Command.Item
                        name="Switch team"
                        callback={() => {
                            selected = 'Switch team selected';
                        }}
                    >
                        <HugeiconsIcon icon={Users} size={16} />
                        Switch team
                    </Command.Item>
                    <Command.Item
                        name="Theme"
                        callback={() => {
                            selected = 'Theme selected';
                        }}
                    >
                        <HugeiconsIcon icon={Moon} size={16} />
                        Theme
                    </Command.Item>
                </Command.Group>
            </Command.Results>
        </Command.Content>
    </Command.Root>
    <p role="status" class="text-sm text-foreground-muted">{selected}</p>
</div>
~~~~

### With Groups

~~~~svelte
<script lang="ts">
    import {
        Add01Icon as Plus,
        Search01Icon as Search,
        Settings01Icon as Settings,
        UserGroupIcon as Users
    } from '@hugeicons/core-free-icons';
    import * as Command from '@mielui/svelte/components/command';
    import HugeiconsIcon from '@mielui/svelte/hugeicons-icon';

    let selected = $state('No command selected');
</script>

<div class="flex flex-col items-center justify-center gap-4">
    <Command.Root>
        <Command.Trigger>
            <HugeiconsIcon icon={Search} size={14} />
            Open palette
        </Command.Trigger>
        <Command.Content>
            <Command.Search placeholder="Search..." />
            <Command.Results>
                <Command.Group heading="Actions">
                    <Command.Item
                        name="New project"
                        callback={() => {
                            selected = 'New project selected';
                        }}
                    >
                        <HugeiconsIcon icon={Plus} size={14} />
                        New project
                    </Command.Item>
                    <Command.Item
                        name="Settings"
                        callback={() => {
                            selected = 'Settings selected';
                        }}
                    >
                        <HugeiconsIcon icon={Settings} size={14} />
                        Settings
                    </Command.Item>
                </Command.Group>
                <Command.Group heading="Users">
                    <Command.Item
                        name="Team"
                        callback={() => {
                            selected = 'Team selected';
                        }}
                    >
                        <HugeiconsIcon icon={Users} size={14} />
                        Team
                    </Command.Item>
                </Command.Group>
            </Command.Results>
        </Command.Content>
    </Command.Root>
    <p role="status" class="text-sm text-foreground-muted">{selected}</p>
</div>
~~~~

For the rendered reference, visit [/docs/components/command](/docs/components/command).
