Headless UI for building
command menus in React.
- Favorites
- SpotifyControl Spotify
- InstagramCheck our instagram
- TwitterCheck our twitter
- Common
- WeatherCheck today's weather
- ShareShare smth
- GithubCheck github
- FramerOpen Framer
- FigmaOpen Figma
- Light modeSwitch to light mode
- Dark modeSwitch to dark mode
- ConfigurationChange smth
How to use it?
This package offers a hook for creating a customized command menu. It returns an object that includes properties for every element in the menu, such as the menu itself, the search input, and a list of all the necessary properties for each menu item which enables you to easily build a command menu tailored to your specific needs.
1import { useCommandMenu } from "commandmenu";
2import { config } from "./config";
3
4const { selectedItem, selectedItemRef, menuProps, searchProps, list } =
5 useCommandMenu({ config })
In order to fully utilize the functionality of this package, you must pass a configuration array that includes all the items you wish to display in the menu. A basic example of this configuration array might look something like the following:
1import type { ConfigData } from "commandmenu";
2import type { IconName } from "components/Icon";
3
4const config: ConfigData<IconName> = [
5 {
6 id: 'github',
7 label: 'Github',
8 icon: 'Github',
9 description: 'Check github',
10 onSelect: () => console.log('github selected')
11 },
12 {
13 id: 'spotifyPlay',
14 label: 'Spotify play',
15 icon: 'Play',
16 description: 'Play songs on Spotify',
17 onSelect: () => console.log('spotify play selected')
18 },
19 {
20 id: 'spotifyNext',
21 label: 'Spotify next',
22 icon: 'Next',
23 description: 'Next song on Spotify',
24 onSelect: () => console.log('spotify next selected')
25 },
26]
Utilizing the props data returned by the hook is a straightforward process. Simply spread the `menuProps` and `searchProps`, then map through the list in order to render all the necessary menu items.
1return (
2 <CommandMenu {...menuProps}>
3 <SearchInput {...searchProps} />
4 <CommandMenuList>
5 {list.map(({ id, label, icon, description }) => {
6 const isSelected = id === selectedItem
7 return (
8 <CommandMenuListItemWrapper
9 key={id}
10 ref={isSelected ? selectedItemRef : null}
11 isSelected={isSelected}
12 >
13 {icon && <CommandMenuListItemIcon name={icon} />}
14 <CommandMenuListItemLabel>{label}</CommandMenuListItemLabel>
15 {description && (
16 <CommandMenuListItemDescription>
17 {description}
18 </CommandMenuListItemDescription>
19 )}
20 </CommandMenuListItemWrapper>
21 )
22 })}
23 </CommandMenuList>
24 </CommandMenu>
25)
Ah, you are looking for
something more advanced...
Grouping and nested menus
Groups
If you wish to group items in your menu, it's easy to do so by wrapping them in a group object configuration. Once you've done this, you're ready to go!
1{
2 id: 'favs',
3 label: 'Favorites',
4 groupItems: [
5 {
6 id: 'github',
7 label: 'Github',
8 icon: 'Github',
9 description: 'Check github',
10 onSelect: () => console.log('open github')
11 },
12 {
13 id: 'spotifyPlay',
14 label: 'Spotify play',
15 icon: 'Play',
16 description: 'Play songs on Spotify',
17 onSelect: () => console.log('spotify play')
18 },
19 {
20 id: 'spotifyNext',
21 label: 'Spotify next',
22 icon: 'Next',
23 description: 'Next song on Spotify',
24 onSelect: () => console.log('spotify next')
25 },
26 ]
27},
Once you've updated the command menu configuration, the final step is to simply render the group elements inside another list. This can be accomplished using code similar to the following:
1return (
2 <CommandMenu {...menuProps}>
3 <SearchInput {...searchProps} />
4 <CommandMenuList>
5 {list.map((item) => {
6 if (isGroupItem(item)) {
7 return (
8 <CommandMenuListGroupItem key={item.id} id="group">
9 <CommandMenuListGroupItemLabel>
10 {item.label}
11 </CommandMenuListGroupItemLabel>
12 <CommandMenuGroupList>
13 {item.groupItems.map((groupItem) => (
14 <CommandMenuListItem
15 key={groupItem.id}
16 selectedItem={selectedItem}
17 selectedItemRef={selectedItemRef}
18 {...groupItem}
19 />
20 ))}
21 </CommandMenuGroupList>
22 </CommandMenuListGroupItem>
23 )
24 }
25 return (
26 <CommandMenuListItem
27 key={item.id}
28 selectedItem={selectedItem}
29 selectedItemRef={selectedItemRef}
30 {...item}
31 />
32 )
33 })}
34 </CommandMenuList>
35 </CommandMenu>
36 )
Nested menus
If you'd like to include multiple options related to a specific item, you can utilize nested menus. You can even add nested menus to each level, as needed. Once you've updated the configuration accordingly, this feature should work seamlessly, allowing you to take your menu functionality to the next level!
1{
2 id: 'spotify',
3 label: 'Spotify',
4 icon: 'Music',
5 description: 'Control Spotify',
6 items: [
7 {
8 id: 'spotifyPlay',
9 label: 'Play',
10 icon: 'Play',
11 onSelect: () => console.log('spotify play selected')
12 },
13 {
14 id: 'spotifyPause',
15 label: 'Pause',
16 icon: 'Pause',
17 onSelect: () => console.log('spotify pasue selected')
18 },
19 {
20 id: 'spotifyNext',
21 label: 'Next',
22 icon: 'ArrowRight',
23 onSelect: () => console.log('spotify next selected')
24 },
25 {
26 id: 'spotifyPrevious',
27 label: 'Previous',
28 icon: 'ArrowLeft',
29 onSelect: () => console.log('spotify prev selected')
30 },
31 ]
32}