1.1.0 • Published 1 year ago

@makisuo/react-cmdk v1.1.0

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

A command palette for React

A package with components for building your dream command palette for your web application.

Watch the YouTube demo or try it out here to get started.

Features

✓ Accessible ✓ Flexible ✓ Good looking ✓ Very fast ✓ Dark & light mode

Installation

npm install react-cmdk

Or if you'd rather use Yarn

yarn add react-cmdk

Example usage

You can compose your command palette pretty much however you like with the included components. But here is an example of a command palette that uses some of the included helpers for a very neat solution.

import "react-cmdk/dist/cmdk.css";
import CommandPalette, { filterItems, getItemIndex } from "react-cmdk";
import { useState } from "react";

const Example = () => {
  const [page, setPage] = useState<"root" | "projects">("root");
  const [open, setOpen] = useState<boolean>(true);
  const [search, setSearch] = useState("");

  const filteredItems = filterItems(
    [
      {
        heading: "Home",
        id: "home",
        items: [
          {
            id: "home",
            children: "Home",
            icon: "HomeIcon",
            href: "#",
          },
          {
            id: "settings",
            children: "Settings",
            icon: "CogIcon",
            href: "#",
          },
          {
            id: "projects",
            children: "Projects",
            icon: "CollectionIcon",
            closeOnSelect: false,
            onClick: () => {
              setPage("projects");
            },
          },
        ],
      },
      {
        heading: "Other",
        id: "advanced",
        items: [
          {
            id: "developer-settings",
            children: "Developer settings",
            icon: "CodeIcon",
            href: "#",
          },
          {
            id: "privacy-policy",
            children: "Privacy policy",
            icon: "SupportIcon",
            href: "#",
          },
          {
            id: "log-out",
            children: "Log out",
            icon: "LogoutIcon",
            onClick: () => {
              alert("Logging out...");
            },
          },
        ],
      },
    ],
    search
  );

  return (
    <CommandPalette
      onChangeSearch={setSearch}
      onChangeOpen={setOpen}
      search={search}
      isOpen={open}
      page={page}
    >
      <CommandPalette.Page id="root">
        {filteredItems.length ? (
          filteredItems.map((list) => (
            <CommandPalette.List key={list.id} heading={list.heading}>
              {list.items.map(({ id, ...rest }) => (
                <CommandPalette.ListItem
                  key={id}
                  index={getItemIndex(filteredItems, id)}
                  {...rest}
                />
              ))}
            </CommandPalette.List>
          ))
        ) : (
          <CommandPalette.FreeSearchAction />
        )}
      </CommandPalette.Page>

      <CommandPalette.Page id="projects">
        {/* Projects page */}
      </CommandPalette.Page>
    </CommandPalette>
  );
};

export default Example;

Opening the command palelette

The package does include a helper hook for opening the command palette, but you can actually open it however you want. Here are some examples.

Helper

const [isOpen, setIsOpen] = useState<boolean>(false);

useHandleOpenCommandPalette(setIsOpen);

Custom

const [isOpen, setIsOpen] = useState<boolean>(false);

useEffect(() => {
  function handleKeyDown(e: KeyboardEvent) {
    if (e.metaKey && e.key === "k") {
      e.preventDefault();
      e.stopPropagation();

      setIsOpen((currentValue) => {
        return !currentValue;
      });
    }
  }

  document.addEventListener("keydown", handleKeyDown);

  return () => {
    document.removeEventListener("keydown", handleKeyDown);
  };
}, []);

API

CommandPalette

nametyperequireddefaultdescription
onChangeSearch(value: string) => voidtrueFunction for setting search value
onChangeOpen(value: boolean) => voidtrueFunction for setting open state
childrenReact.ReactNodetrueChildren of command palette
isOpenbooleantrueOpen state
searchstringtrueSearch state
placeholderstringfalse"Search"Search field placeholder
pagestringfalseThe current page id
renderLinkRenderLinkfalseFunction for customizing rendering of links
footerReact.ReactNodefalseFooter component
selectednumberfalseThe current selected item index
onChangeSelected(value: number) => voidfalseFunction for setting selected item index

CommandPalette.Page

FYI. Using pages is completely optional

nametyperequireddefaultdescription
idstringtrueA unique page id
childrenReact.ReactNodetrueChildren of the list
searchPrefixstring[]falsePrefix to the left of the search bar
onEscape() => voidfalseFunction that runs upon clicking escape

CommandPalette.List

nametyperequireddefaultdescription
childrenReact.ReactNodetrueChildren of the list
headingstringfalseHeading of the list

CommandPalette.ListItem

nametyperequireddefaultdescription
indexnumbertrueIndex for list item
closeOnSelectbooleanfalseWhether to close the command palette upon click
icon(IconName, React.FC)falsefalseIcon for list item
iconTypeIconTypefalse"solid"Icon for list item
showTypebooleanfalsetrueWhether to show the item type
disabledbooleanfalseWhether the item is disabled
keywordsArrayfalseUnderlying search keywords for the list item

The list item also extends the HTMLAnchorElement & HTMLButtonElement types

CommandPalette.FreeSearchAction

nametyperequireddefaultdescription
indexnumberfalse0Index for list item
labelstringfalse"Search for"Button label

The search action also extends the HTMLAnchorElement & HTMLButtonElement types

RenderLink

(
  props: DetailedHTMLProps<
    AnchorHTMLAttributes<HTMLAnchorElement>,
    HTMLAnchorElement
  >
) => ReactNode;

JsonStructure

Array of

nametyperequireddefaultdescription
idstringtrueId for list
itemsArray<JsonStructureItem>trueItems for list
headingstringfalseHeading for list

JsonStructureItem

CommandPalette.ListItem

Omits index & extends

nametyperequireddefaultdescription
idstringtrueId for list item

Utils

getItemIndex

A function for getting the current index of a item within the json structure

(items: JsonStructure, listItemId: string, startIndex = 0) => number;

filterItems

A function for filtering the json structure from a search string

(
  items: JsonStructure,
  search: string,
  options?: { filterOnListHeading: boolean }
) => JsonStructure;

renderJsonStructure

A function for rendering a json structure

(items: JsonStructure) => JSX.Element[]

useHandleOpenCommandPalette

(fn: React.Dispatch<React.SetStateAction<boolean>>) => void

Maintainers