Personalización

Personalización

Cmd+kit se configura en código. La superficie principal de personalización es la propia estructura de comandos, seguida de mensajes, tema, renderers y fuentes asíncronas.

Si quieres explorar estos ajustes con una interfaz guiada antes de llevarlos a código, consulta la documentación del playground.

Define secciones e ítems

const sections = [
  {
    id: "navigation",
    title: "Navigation",
    items: [
      {
        id: "dashboard",
        title: "Dashboard",
        subtitle: "Open the main workspace",
        href: "/dashboard",
        keywords: ["home", "workspace"]
      }
    ]
  }
];
const sections = [
  {
    id: "search",
    title: "Search",
    items: [
      {
        id: "docs",
        title: "Documentation",
        children: [
          {
            id: "guides",
            title: "Guides",
            items: [
              { id: "api", title: "API reference" }
            ]
          }
        ]
      }
    ]
  }
];

Tokens de tema

<CommandPalette
  sections={sections}
  theme={{
    light: {
      accentColor: "#0fa6d8",
      backgroundColor: "#ffffff",
      textColor: "#0e1720"
    },
    dark: {
      accentColor: "#12b5e5",
      backgroundColor: "#0f1720",
      textColor: "#f5fbff",
      mutedColor: "#9fb4c4",
      borderColor: "#264152",
      overlayColor: "rgba(4, 9, 13, 0.64)",
      radius: "22px",
      shadow: "0 24px 80px rgba(0, 0, 0, 0.42)"
    }
  }}
/>

Variables CSS

import { createThemeCssText } from "@cmd-kit/core";

const themes = {
  light: { accentColor: "#0fa6d8", backgroundColor: "#ffffff" },
  dark: { accentColor: "#12b5e5", backgroundColor: "#0f1720" }
};

const darkCss = createThemeCssText(themes.dark);
const lightCss = createThemeCssText(themes.light);

const themeBlock = `:root {
${darkCss}
}

html[data-theme="light"] {
${lightCss}
}`;

Mensajes

<CommandPalette
  sections={sections}
  messages={{
    searchPlaceholder: "Busca comandos",
    noResults: "No hay resultados para esta búsqueda.",
    closeLabel: "Cerrar palette"
  }}
/>

Overrides de render y estilo

<CommandPalette
  classNames={{
    dialog: "palette-shell",
    item: "palette-item",
    emptyState: "palette-empty"
  }}
  renderers={{
    title: ({ activeTitle, breadcrumbs }) => (
      <span>{breadcrumbs.join(" / ") || activeTitle}</span>
    ),
    emptyState: ({ query }) => <span>Sin resultados para "{query}"</span>
  }}
  sections={sections}
/>

Fuente asíncrona

<CommandPalette
  source={async () => {
    const response = await fetch("/api/commands");
    return response.json();
  }}
  title="Comandos del workspace"
/>

FAQ

¿Debo meter componentes de icono dentro del modelo de datos?

Normalmente no. Mantén el modelo agnóstico y mapea iconos en renderers o slots.

¿Qué estrategia de estilos es más limpia?

Usa theme para tokens de diseño comunes y classNames para control CSS por slot.

¿Puedo combinar navegación anidada con source asíncrono?

Sí, siempre que la respuesta asíncrona respete el mismo shape de comandos.

¿Cómo localizo placeholder y estado vacío?

Sobrescribe messages desde tu capa de i18n en vez de hardcodearlo en los datos.

¿Cómo mantener renderers custom sin que se vuelvan inmantenibles?

Deja la lógica de negocio en la generación de comandos y usa renderers solo para presentación.