kmenu
v2.0.0
Published
π Animated and accessible cmdk interface
Downloads
2,982
Maintainers
Readme
Consulting
If you're a startup or founder using this for your application and need some help setting it up, or perhaps even need a separate cmdk interface tailored to your application, you can reach out to at [email protected].
Quickstart
View the official documentation for more thorough examples and documentation.
Having trouble? Unsure of something? Feel free to ask away in the discussions.
Install the npm package:
npm add kmenu
yarn add kmenu
pnpm add kmenu
Using the Provider
After you install, you must wrap your application around the MenuProvider
component. If your application has some values (padding/margin/etc) which override the styles of the menu, you need to explicitly define the height of each command component and each section in your code. Here's a look:
| Parameter | Description | Type | Optional | | ---------- | ---------------------------------------------------- | ---------- | -------- | | dimensions | Height values of different elements in the menu (px) | Dimensions | β |
Now, here's a look at the dimensions object:
| Parameter | Description | Type | Default | Optional | | ------------- | ----------------------------------------------------------------- | ------ | ------- | -------- | | commandHeight | The height of each command in the palette (px) | number | 54 | β | | sectionHeight | The height of each category/section in the palette (px) | number | 31 | β | | commands | The maximum number of commands displayed on menu without overflow | number | 5 | β |
Here's how you'd use your menu provider:
import { MenuProvider, Dimensions } from 'kmenu'
export default ({ children }) => {
const dimensions: Dimensions = {}
return <MenuProvider dimensions={dimensions}>{children}</MenuProvider>
}
Commands
The commands are broken up into two arrays: an array that contains the different categories of the commands, and another array contains the commands itself. Here's how you can define categories:
| Parameter | Description | Type | Optional | | ----------- | ----------------------------------------------------------------------- | ------- | -------- | | category | The name of the category the command will be displayed in | string | β | | commands | An array of commands passed onto the category | Command | β | | subCommands | An array of commands passed onto the category only accessible by search | Command | β |
Here's how you create commands:
| Parameter | Description | Type | Optional | | --------------- | --------------------------------------------------------- | ------------ | -------- | | icon | The icon displayed next to the command | ReactElement | β | | text | The text displayed on the command | string | β | | perform | The action to perform | void | β | | href | The link to open | void | β | | newTab | Whether or not the link should open in a new tab | boolean | β | | keywords | Search keywords for the command | string | β | | shorcuts | The keyboard shortcuts displayed on the command | Shortcut | β | | closeOnComplete | Whether the menu should close after command executes | boolean | β | | anchor | Allow for custom HTML to be passed as the anchor property | NavLink | β | | checkbox | Add a checkbox to the command | Checkbox | β |
We can create our commands array like this:
import type { Command } from 'kmenu'
const main: Command[] = [
{
category: 'Utility',
commands: [
{
icon: <Dashboard />,
text: 'Dashboard',
href: '/dashboard',
keywords: ['home', 'back'],
},
{
icon: <Cloud />,
text: 'Deployments',
href: '/deployments',
},
{
icon: <ArrowLeft />,
text: 'Previous',
perform: () => navigateToPreviousPage(),
keywords: ['back']
},
],
subCommands: [
{
icon: <ExternalLink />,
text: 'Home',
href: '/',
newTab: true,
},
],
},
]
Shortcuts
Each shortcut can have two target keys and a modifier:
| Parameter | Description | Type | Optional | | --------- | ----------------------------------------------------- | -------------------------------------- | -------- | | keys | The key(s) that the shortcut is listening for | [string, string?] (must be valid) | β | | modifier | The modifier key which can will activate the shortcut | string (must be valid) or ReactElement | β |
Command Wrapper
Be sure to wrap ALL your menus around a CommandWrapper
component. This component contains things like the breadcrumbs and the search bar. You can pass in a default value for the input on the command wrapper:
| Parameter | Description | Type | Optional | | ------------ | ------------------------------ | ------ | -------- | | defaultValue | The default value on the input | string | β |
Command Menu
Here are all the options available on the menu:
| Parameter | Description | Type | Optional | | ------------------ | -------------------------------------------- | ------------ | -------- | | commands | The commands for this menu to display | Command[] | β | | index | The index of this menu | number | β | | crumbs | The current path of the command menu | string[] | β | | preventSearch | Disable filtering results for the menu | string | β | | loadingPlaceholder | Element to be displayed while commands load | ReactElement | β | | loadingState | Whether or not the data is currently loading | boolean | β | | placeholder | The placeholder text on this particular menu | string | β |
The index is the index of this menuβif you only have a single menu, set this to one. This number is used for opening and closing multiple menus, whenever you want to open a sub menu simply use the setOpen
command and input the index of the menu you'd like to open. For more information on this, see nested menus.
useCommands
After you define your components, you must input them into the useCommands
hook. Learn more about it here.
export default () => {
const main = [
/* ... */
];
const [mainCommands] = useCommands(main);
return (
<CommandWrapper>
<CommandMenu commands={mainCommands} index={1} crumbs={['Home']} />
</CommandWrapper>
);
};
That's about all the configuration you'll need to do in order to get a basic command menu to work.
The possibilities are with these menus infinite: you can add custom loading states, sub-commands, and so much more. For a full list, check out the examples.
useKmenu Hook
useKmenu
is a utility hook that adds utility and gives you information about the current status of the menu. You can use these for a multitude of different things such as nested routes on the command menu or for toggling the menu through a button on your UI.
Here's a list of all the information it provides:
| Parameter | Description | Type | | --------- | --------------------------------------------------------------------- | ------------------------------------------------- | | input | The current text in the search bar of the menu that is currently open | string | | setInput | The setter function to change the input | Dispatch<SetStateAction<string>> | | isOpen | Whether or not the menu is currently open | boolean | | open | The index of the menu is currently open | number | | setOpen | The setter function to change the open state | (index: number, preventAnimate?: boolean) => void | | toggle | The function for toggling the main menu open/close | void |
Here's an example of how you can toggle the menu open with the click of a button:
import { useKmenu } from 'kmenu'
export default () => {
const { toggle } = useKmenu()
return <button onClick={toggle}>Toggle Menu</button>
}
REMINDER: YOUR APPLICATION OR PARENT COMPONENT MUST BE WRAPPED IN THE MENUPROVIDER
Examples
In an attempt to showcase everything this menu can do, examples/src/kmenu includes an ever-growing list some things you can do with kmenu:
This list is ever-growing. If there's something you ever want to add, any and all pull requests are always welcomed.