> ## Documentation Index
> Fetch the complete documentation index at: https://araf.badr.co.id/llms.txt
> Use this file to discover all available pages before exploring further.

# Command

> A searchable command palette (⌘K) for quickly navigating, running actions, and filtering options — keyboard-first by design.

## Overview

<div style={{padding:"28px 24px",background:"#f9fafb",borderRadius:"12px",border:"1px solid #e5e7eb",display:"flex",justifyContent:"center"}}>
  <div style={{background:"#fff",border:"1px solid #E5E7EB",borderRadius:"12px",boxShadow:"0 8px 32px rgba(0,0,0,0.12)",width:"100%",maxWidth:"400px",overflow:"hidden",fontFamily:"Inter,sans-serif"}}>
    <div style={{display:"flex",alignItems:"center",gap:"8px",padding:"12px 14px",borderBottom:"1px solid #F2F4F7"}}>
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#9CA3AF" strokeWidth="2">
        <circle cx="11" cy="11" r="8" />

        <line x1="21" y1="21" x2="16.65" y2="16.65" />
      </svg>

      <input readOnly placeholder="Search commands..." style={{border:"none",outline:"none",fontSize:"14px",color:"#344054",width:"100%",background:"transparent"}} />

      <kbd style={{fontSize:"11px",color:"#9CA3AF",border:"1px solid #E5E7EB",borderRadius:"4px",padding:"2px 5px",background:"#F9FAFB"}}>ESC</kbd>
    </div>

    <div style={{padding:"4px"}}>
      <div style={{fontSize:"11px",color:"#9CA3AF",fontWeight:500,padding:"8px 10px 4px"}}>Navigation</div>

      {[
                  {icon:"M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z M9 22V12h6v10",label:"Home",shortcut:"G H"},
                  {icon:"M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2 M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z",label:"Profile",shortcut:"G P"},
                ].map((item,i) => (
                  <div key={i} style={{display:"flex",alignItems:"center",gap:"8px",padding:"7px 10px",borderRadius:"6px",background:i===0?"#F0F9FF":"transparent",cursor:"pointer"}}>
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={i===0?"#0479CE":"#667085"} strokeWidth="2">
                      {item.icon.split("M").filter(Boolean).map((seg,j) => <path key={j} d={"M"+seg}/>)}
                    </svg>
                    <span style={{fontSize:"13px",color:i===0?"#0479CE":"#344054",flex:1}}>{item.label}</span>
                    <kbd style={{fontSize:"10px",color:"#9CA3AF",border:"1px solid #E5E7EB",borderRadius:"3px",padding:"1px 4px",background:"#F9FAFB"}}>{item.shortcut}</kbd>
                  </div>
                ))}

      <div style={{fontSize:"11px",color:"#9CA3AF",fontWeight:500,padding:"8px 10px 4px"}}>Actions</div>

      {[
                  {icon:"M12 5v14 M5 12h14",label:"New document"},
                  {icon:"M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z M17 21v-8H7v8 M7 3v5h8",label:"Save"},
                ].map((item,i) => (
                  <div key={i} style={{display:"flex",alignItems:"center",gap:"8px",padding:"7px 10px",borderRadius:"6px",cursor:"pointer"}}>
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#667085" strokeWidth="2">
                      {item.icon.split("M").filter(Boolean).map((seg,j) => <path key={j} d={"M"+seg}/>)}
                    </svg>
                    <span style={{fontSize:"13px",color:"#344054"}}>{item.label}</span>
                  </div>
                ))}
    </div>

    <div style={{borderTop:"1px solid #F2F4F7",padding:"8px 14px",display:"flex",gap:"12px"}}>
      <span style={{fontSize:"11px",color:"#9CA3AF"}}>↑↓ navigate</span>
      <span style={{fontSize:"11px",color:"#9CA3AF"}}>↵ select</span>
      <span style={{fontSize:"11px",color:"#9CA3AF"}}>ESC close</span>
    </div>
  </div>
</div>

**Command** is a keyboard-first command palette — typically opened with `⌘K` — that allows users to search, navigate, and trigger actions without leaving the keyboard. It supports grouped results, icons, and keyboard shortcuts.

***

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @araf-ds/core
  ```

  ```bash yarn theme={null}
  yarn add @araf-ds/core
  ```

  ```bash pnpm theme={null}
  pnpm add @araf-ds/core
  ```
</CodeGroup>

***

## Usage

```tsx theme={null}
import {
  Command,
  CommandDialog,
  CommandInput,
  CommandList,
  CommandEmpty,
  CommandGroup,
  CommandItem,
  CommandShortcut,
  CommandSeparator,
} from "@araf-ds/core"

export default function Example() {
  const [open, setOpen] = useState(false)

  // Open with ⌘K
  useEffect(() => {
    const down = (e: KeyboardEvent) => {
      if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
        e.preventDefault()
        setOpen(prev => !prev)
      }
    }
    document.addEventListener("keydown", down)
    return () => document.removeEventListener("keydown", down)
  }, [])

  return (
    <CommandDialog open={open} onOpenChange={setOpen}>
      <CommandInput placeholder="Type a command or search..." />
      <CommandList>
        <CommandEmpty>No results found.</CommandEmpty>
        <CommandGroup heading="Navigation">
          <CommandItem>
            <HomeIcon size={14} />
            Home
            <CommandShortcut>G H</CommandShortcut>
          </CommandItem>
          <CommandItem>
            <UserIcon size={14} />
            Profile
            <CommandShortcut>G P</CommandShortcut>
          </CommandItem>
        </CommandGroup>
        <CommandSeparator />
        <CommandGroup heading="Actions">
          <CommandItem>
            <PlusIcon size={14} />
            New document
          </CommandItem>
        </CommandGroup>
      </CommandList>
    </CommandDialog>
  )
}
```

***

## Variants

### Inline (Embedded in Page)

Use `Command` directly (without `CommandDialog`) to embed the palette inline — useful for search inputs, comboboxes, and filter panels.

<div style={{padding:"24px",background:"#f9fafb",borderRadius:"12px",border:"1px solid #e5e7eb",display:"flex",justifyContent:"center"}}>
  <div style={{background:"#fff",border:"1px solid #E5E7EB",borderRadius:"10px",width:"100%",maxWidth:"320px",overflow:"hidden",fontFamily:"Inter,sans-serif"}}>
    <div style={{display:"flex",alignItems:"center",gap:"8px",padding:"10px 12px",borderBottom:"1px solid #F2F4F7"}}>
      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#9CA3AF" strokeWidth="2">
        <circle cx="11" cy="11" r="8" />

        <line x1="21" y1="21" x2="16.65" y2="16.65" />
      </svg>

      <span style={{fontSize:"13px",color:"#9CA3AF"}}>Search frameworks...</span>
    </div>

    <div style={{padding:"4px"}}>
      {["Next.js","SvelteKit","Nuxt.js","Remix","Astro"].map((item,i) => (
                  <div key={i} style={{display:"flex",alignItems:"center",gap:"8px",padding:"7px 10px",borderRadius:"6px",background:i===0?"#F0F9FF":"transparent",cursor:"pointer"}}>
                    {i===0 && <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#0479CE" strokeWidth="2.5"><polyline points="20 6 9 17 4 12"/></svg>}
                    {i!==0 && <div style={{width:"12px"}}></div>}
                    <span style={{fontSize:"13px",color:i===0?"#0479CE":"#344054"}}>{item}</span>
                  </div>
                ))}
    </div>
  </div>
</div>

```tsx theme={null}
<Command className="rounded-lg border shadow-md w-[320px]">
  <CommandInput placeholder="Search frameworks..." />
  <CommandList>
    <CommandEmpty>No framework found.</CommandEmpty>
    <CommandGroup>
      {frameworks.map(fw => (
        <CommandItem
          key={fw.value}
          value={fw.value}
          onSelect={setValue}
        >
          <CheckIcon
            className={cn(value === fw.value ? "opacity-100" : "opacity-0")}
            size={12}
          />
          {fw.label}
        </CommandItem>
      ))}
    </CommandGroup>
  </CommandList>
</Command>
```

### Dialog (Global ⌘K Palette)

The most common pattern — full-screen overlay opened with a keyboard shortcut.

```tsx theme={null}
// Trigger button shown in the UI
<Button
  variant="outline"
  onClick={() => setOpen(true)}
  className="gap-2 text-muted-foreground"
>
  <SearchIcon size={14} />
  Search...
  <kbd className="ml-auto text-xs border rounded px-1">⌘K</kbd>
</Button>

<CommandDialog open={open} onOpenChange={setOpen}>
  <CommandInput placeholder="Type a command or search..." />
  <CommandList>
    <CommandEmpty>No results found.</CommandEmpty>
    <CommandGroup heading="Suggestions">
      <CommandItem onSelect={() => router.push("/dashboard")}>
        <LayoutDashboardIcon size={14} /> Dashboard
      </CommandItem>
      <CommandItem onSelect={() => router.push("/settings")}>
        <SettingsIcon size={14} /> Settings
        <CommandShortcut>⌘,</CommandShortcut>
      </CommandItem>
    </CommandGroup>
  </CommandList>
</CommandDialog>
```

***

## API Reference

### Command

<ParamField path="value" type="string">
  Controlled selected item value.
</ParamField>

<ParamField path="onValueChange" type="(value: string) => void">
  Callback fired when the selected item changes.
</ParamField>

<ParamField path="filter" type="(value: string, search: string) => number">
  Custom filter function. Return `1` to show, `0` to hide. Default: fuzzy search.
</ParamField>

<ParamField path="shouldFilter" type="boolean" default="true">
  Set to `false` to disable built-in filtering (handle externally with async search).
</ParamField>

### CommandDialog

<ParamField path="open" type="boolean">
  Controlled open state.
</ParamField>

<ParamField path="onOpenChange" type="(open: boolean) => void">
  Callback fired when open state changes.
</ParamField>

### CommandInput

<ParamField path="placeholder" type="string">
  Placeholder text shown when empty.
</ParamField>

<ParamField path="value" type="string">
  Controlled input value.
</ParamField>

### CommandItem

<ParamField path="value" type="string">
  The value used for filtering and selection.
</ParamField>

<ParamField path="onSelect" type="(value: string) => void">
  Callback fired when the item is selected (Enter or click).
</ParamField>

<ParamField path="disabled" type="boolean" default="false">
  Disables the item.
</ParamField>

### CommandGroup

<ParamField path="heading" type="string">
  Group label shown above the items.
</ParamField>

***

## Accessibility

* `CommandDialog` uses `role="dialog"` with `aria-modal="true"`
* `CommandInput` is a search input with `role="combobox"` and `aria-expanded`
* `CommandList` has `role="listbox"`; each `CommandItem` has `role="option"`
* Keyboard: Arrow Up/Down navigates, Enter selects, Escape closes, typing filters
* `CommandEmpty` is announced by screen readers when no results match

***

## Do's & Don'ts

<CardGroup cols={2}>
  <Card title="Do" icon="check" iconType="solid" color="#16A34A">
    * Register `⌘K` / `Ctrl+K` globally to open the command palette
    * Group items with `CommandGroup` and clear `heading` labels
    * Show a visible keyboard shortcut hint in the UI (e.g. a button with `⌘K` badge)
    * Use `shouldFilter={false}` for server-side or async search
  </Card>

  <Card title="Don't" icon="xmark" iconType="solid" color="#DC2626">
    * Don't put destructive actions in the command palette without confirmation
    * Don't list more than 20–30 items without grouping or filtering
    * Don't use Command as a regular dropdown — use `Select` or `DropdownMenu`
    * Don't forget to close the dialog after an action is selected
  </Card>
</CardGroup>
