Ir al contenido

Command

Una paleta de comandos (⌘K) para búsqueda rápida y acciones. Soporta navegación por teclado, elementos agrupados, páginas anidadas, y patrones tanto basados en datos como de componentes compuestos.

import { Command } from 'asterui'

Uso Básico

Paleta de comandos basada en datos con elementos agrupados.

import { Command, Button } from 'asterui'
import { useState } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  
  const items = [
    { key: 'new-file', label: 'Create New File', group: 'Actions' },
    { key: 'new-folder', label: 'Create New Folder', group: 'Actions' },
    { key: 'search', label: 'Search Files', group: 'Actions' },
    { key: 'home', label: 'Go to Home', group: 'Navigation' },
    { key: 'settings', label: 'Open Settings', group: 'Navigation' },
    { key: 'profile', label: 'View Profile', group: 'Navigation' },
  ];
  
  return (
      <>
        <Button color="primary" onClick={() => setOpen(true)}>
          Open Command Palette
        </Button>
        <Command
          open={open}
          onOpenChange={setOpen}
          items={items}
          placeholder="Type a command or search..."
        />
      </>
    )
}

export default App

Componentes Compuestos

Construye paletas de comandos usando componentes compuestos para más control.

import { Command, Button } from 'asterui'
import { useState } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  
  return (
      <>
        <Button color="primary" onClick={() => setOpen(true)}>
          Open Command Palette
        </Button>
        <Command open={open} onOpenChange={setOpen}>
          <Command.List>
            <Command.Empty>No results found</Command.Empty>
            <Command.Group heading="Actions">
              <Command.Item onSelect={() => alert('Creating file...')}>
                Create New File
              </Command.Item>
              <Command.Item onSelect={() => alert('Creating folder...')}>
                Create New Folder
              </Command.Item>
            </Command.Group>
            <Command.Separator />
            <Command.Group heading="Navigation">
              <Command.Item onSelect={() => alert('Going home...')}>
                Go to Home
              </Command.Item>
              <Command.Item onSelect={() => alert('Opening settings...')}>
                Open Settings
              </Command.Item>
            </Command.Group>
          </Command.List>
        </Command>
      </>
    )
}

export default App

Con Iconos

Agrega iconos a los elementos de comando para contexto visual.

import { Command, Button } from 'asterui'
import { useState } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  
  const items = [
    { key: 'new-file', label: 'Create New File', group: 'Actions', icon: <FileIcon /> },
    { key: 'new-folder', label: 'Create New Folder', group: 'Actions', icon: <FolderIcon /> },
    { key: 'search', label: 'Search Files', group: 'Actions', icon: <SearchIcon /> },
    { key: 'home', label: 'Go to Home', group: 'Navigation', icon: <HomeIcon /> },
    { key: 'settings', label: 'Open Settings', group: 'Navigation', icon: <SettingsIcon /> },
  ];
  
  return (
      <>
        <Button color="primary" onClick={() => setOpen(true)}>
          Open Command Palette
        </Button>
        <Command
          open={open}
          onOpenChange={setOpen}
          items={items}
          placeholder="Type a command or search..."
        />
      </>
    )
}

export default App

Palabras Clave de Búsqueda

Agrega palabras clave extra para hacer que los elementos sean encontrables por términos alternativos.

import { Command, Button } from 'asterui'
import { useState } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  
  const items = [
    {
      key: 'new-file',
      label: 'Create New File',
      group: 'Actions',
      keywords: ['add', 'create', 'new', 'file', 'document']
    },
    {
      key: 'search',
      label: 'Search Files',
      group: 'Actions',
      keywords: ['find', 'lookup', 'query']
    },
    {
      key: 'settings',
      label: 'Open Settings',
      group: 'Navigation',
      keywords: ['preferences', 'config', 'options']
    },
    {
      key: 'profile',
      label: 'View Profile',
      group: 'Navigation',
      keywords: ['user', 'account', 'me']
    },
  ];
  
  return (
      <>
        <Button color="primary" onClick={() => setOpen(true)}>
          Open (try searching "preferences")
        </Button>
        <Command
          open={open}
          onOpenChange={setOpen}
          items={items}
          placeholder="Try 'preferences' or 'config'..."
        />
      </>
    )
}

export default App

Páginas Anidadas

Navega a subpáginas con soporte de navegación hacia atrás. Presiona Retroceso (cuando la búsqueda está vacía) o haz clic en la flecha de retroceso para regresar.

import { Command, Button } from 'asterui'
import { useState } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  
  return (
      <>
        <Button color="primary" onClick={() => setOpen(true)}>
          Open Command Palette
        </Button>
        <Command open={open} onOpenChange={setOpen}>
          <Command.List>
            <Command.Empty>No results found</Command.Empty>
  
            {/* Root page content */}
            <Command.Group heading="Quick Actions">
              <Command.Item onSelect={() => alert('Creating file...')}>
                Create New File
              </Command.Item>
              <Command.Item onSelect={() => alert('Searching...')}>
                Search Files
              </Command.Item>
            </Command.Group>
            <Command.Separator />
            <Command.Group heading="Navigate">
              <Command.Item value="settings-menu">
                Settings →
              </Command.Item>
              <Command.Item value="theme-menu">
                Theme →
              </Command.Item>
            </Command.Group>
  
            {/* Settings page */}
            <Command.Page id="settings">
              <Command.Group heading="Settings">
                <Command.Item onSelect={() => alert('Opening account settings...')}>
                  Account
                </Command.Item>
                <Command.Item onSelect={() => alert('Opening privacy settings...')}>
                  Privacy
                </Command.Item>
                <Command.Item onSelect={() => alert('Opening notification settings...')}>
                  Notifications
                </Command.Item>
              </Command.Group>
            </Command.Page>
  
            {/* Theme page */}
            <Command.Page id="theme">
              <Command.Group heading="Choose Theme">
                <Command.Item onSelect={() => alert('Theme set to Light')}>
                  Light
                </Command.Item>
                <Command.Item onSelect={() => alert('Theme set to Dark')}>
                  Dark
                </Command.Item>
                <Command.Item onSelect={() => alert('Theme set to System')}>
                  System
                </Command.Item>
              </Command.Group>
            </Command.Page>
          </Command.List>
        </Command>
      </>
    )
}

export default App

Elementos Deshabilitados

Deshabilita elementos específicos para prevenir la selección.

import { Command, Button } from 'asterui'
import { useState } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  
  const items = [
    { key: 'new-file', label: 'Create New File', group: 'Actions' },
    { key: 'new-folder', label: 'Create New Folder', group: 'Actions', disabled: true },
    { key: 'search', label: 'Search Files', group: 'Actions' },
    { key: 'delete', label: 'Delete Files', group: 'Danger', disabled: true },
  ];
  
  return (
      <>
        <Button color="primary" onClick={() => setOpen(true)}>
          Open Command Palette
        </Button>
        <Command
          open={open}
          onOpenChange={setOpen}
          items={items}
          placeholder="Some items are disabled..."
        />
      </>
    )
}

export default App

Atajo Personalizado

Cambia el atajo de teclado global de ⌘K a otra tecla.

import { Command, Button, Space } from 'asterui'
import { useState } from 'react'

function App() {
  const [open1, setOpen1] = useState(false);
  const [open2, setOpen2] = useState(false);
  
  const items = [
    { key: 'action1', label: 'Action 1' },
    { key: 'action2', label: 'Action 2' },
  ];
  
  return (
      <>
        <Space direction="horizontal" size="sm">
          <Button onClick={() => setOpen1(true)}>
            Default (⌘K)
          </Button>
          <Button onClick={() => setOpen2(true)}>
            Custom (⌘J)
          </Button>
        </Space>
        <Command
          open={open1}
          onOpenChange={setOpen1}
          items={items}
          placeholder="Default shortcut ⌘K..."
        />
        <Command
          open={open2}
          onOpenChange={setOpen2}
          items={items}
          shortcut={['j']}
          placeholder="Custom shortcut ⌘J..."
        />
      </>
    )
}

export default App

Filtro Personalizado

Proporciona una función de filtro personalizada para lógica de coincidencia avanzada.

import { Command, Button } from 'asterui'
import { useState } from 'react'

function App() {
  const [open, setOpen] = useState(false);
  
  const items = [
    { key: 'apple', label: 'Apple', keywords: ['fruit', 'red'] },
    { key: 'banana', label: 'Banana', keywords: ['fruit', 'yellow'] },
    { key: 'carrot', label: 'Carrot', keywords: ['vegetable', 'orange'] },
    { key: 'date', label: 'Date', keywords: ['fruit', 'brown'] },
  ];
  
  // Custom filter that only matches from the start of words
  const customFilter = (value: string, search: string, keywords?: string[]) => {
    const searchLower = search.toLowerCase();
    if (value.toLowerCase().startsWith(searchLower)) return true;
    return (keywords || []).some(k => k.toLowerCase().startsWith(searchLower));
  };
  
  return (
      <>
        <Button color="primary" onClick={() => setOpen(true)}>
          Open (prefix matching only)
        </Button>
        <Command
          open={open}
          onOpenChange={setOpen}
          items={items}
          filter={customFilter}
          placeholder="Type 'fr' for fruits..."
        />
      </>
    )
}

export default App
PropiedadDescripciónTipoPredeterminado
openEstado abierto controladoboolean-
onOpenChangeCallback cuando cambia el estado abierto(open: boolean) => void-
defaultOpenEstado abierto predeterminado (no controlado)booleanfalse
itemsConfiguración de elementos basada en datosCommandItemConfig[]-
filterFunción de filtro personalizada(value: string, search: string, keywords?: string[]) => boolean-
loopBucle de navegación por teclado en los bordesbooleantrue
shortcutTecla(s) de atajo de teclado globalstring[]['k']
placeholderMarcador de posición de entrada de búsquedastring'Type a command or search...'
emptyMessageMensaje cuando no se encuentran resultadosReactNode'No results found.'
data-testidID de prueba para pruebasstring-

Cuando se usa la prop items basada en datos:

PropiedadDescripciónTipoPredeterminado
keyClave única para el elementostring-
labelEtiqueta de visualizaciónReactNode-
groupNombre del grupo para categorizaciónstring-
keywordsPalabras clave de búsqueda adicionalesstring[]-
disabledDeshabilitar el elementobooleanfalse
onSelectCallback cuando se selecciona el elemento() => void-
iconElemento de icono a mostrarReactNode-
data-testidID de prueba para pruebasstring-

Para más control, usa componentes compuestos:

ComponenteDescripción
Command.ListContenedor para grupos y elementos
Command.GroupAgrupa elementos con encabezado opcional
Command.ItemElemento de comando seleccionable
Command.EmptyMostrado cuando no hay resultados coincidentes
Command.PagePágina anidada para navegación
Command.SeparatorSeparador visual entre secciones
  • Usa elemento nativo <dialog> para captura de foco y manejo de ESC
  • La entrada de búsqueda tiene role="combobox" con atributos ARIA apropiados
  • La lista usa role="listbox" con elementos role="option"
  • Navegación por teclado con teclas de Flecha, Enter para seleccionar, Escape para cerrar
  • aria-activedescendant rastrea el elemento resaltado
  • Los grupos usan role="group" con aria-label
  • ⌘K / Ctrl+K - Abrir paleta de comandos (personalizable)
  • - Navegar elementos
  • Enter - Seleccionar elemento resaltado
  • Escape - Cerrar paleta (o retroceder en página anidada)
  • Retroceso - Retroceder a página anterior (cuando la búsqueda está vacía)