Menu

Menu allows to create a dropdown list of options.

Source
Theme Source
  • Menu - The Menu component with context.
  • MenuTrigger - The trigger for the Menu.
  • MenuContent - The content for the Menu as popover.
  • MenuItem - The item for the Menu.
import { 
	Menu,
    MenuItem,
    MenuContent,
    MenuTrigger
 } from "@dreamy-ui/react";

Basic usage of Menu.

<Menu>
    <MenuTrigger>
        <Button>Open Menu</Button>
    </MenuTrigger>
    <MenuContent>
        <MenuItem icon={<IoAdd />} command="{actionKey} n">Add new</MenuItem>
        <MenuItem icon={<LuAlarmClock />} command="{actionKey} a">Set alarm</MenuItem>
        <MenuItem icon={<LuBattery />} command="{actionKey} b">Battery</MenuItem>
        <MenuItem icon={<LuTrash />} command="{actionKey} d">Delete</MenuItem>
    </MenuContent>
</Menu>

You can change where the Menu is placed by using the placement prop. Use icon prop to place an icon on the beginning or the item and comamnd to show keybinding to the item. Using {actionKey} in command will automatically replace it with the action key of the user's operating system.

<Menu placement="bottom-start">
    <MenuTrigger>
        <Button>Open Menu</Button>
    </MenuTrigger>
    <MenuContent>
        <MenuItem icon={<IoAdd />} command="{actionKey} n">Add new</MenuItem>
        <MenuItem icon={<LuAlarmClock />} command="{actionKey} a">Set alarm</MenuItem>
        <MenuItem icon={<LuBattery />} command="{actionKey} b">Battery</MenuItem>
        <MenuItem icon={<LuTrash />} command="{actionKey} d">Delete</MenuItem>
    </MenuContent>
</Menu>

Menu comes with 4 different sizes.

{["xs", "sm", "md", "lg"].map((size) => (
    <Menu key={size} size={size}>
        <MenuTrigger>
            <Button>Open Menu</Button>
        </MenuTrigger>
        <MenuContent>
            <MenuItem icon={<IoAdd />} command="{actionKey} n">Add new</MenuItem>
            <MenuItem icon={<LuAlarmClock />} command="{actionKey} a">Set alarm</MenuItem>
            <MenuItem icon={<LuBattery />} command="{actionKey} b">Battery</MenuItem>
            <MenuItem icon={<LuTrash />} command="{actionKey} d">Delete</MenuItem>
        </MenuContent>
    </Menu>
))}

You can use a custom link component with menu item but polymorphic props like as, asComp and asChild.

<Menu placement="bottom-start">
    <MenuTrigger>
        <Button w={"fit-content"}>Open Menu</Button>
    </MenuTrigger>
    <MenuContent>
        <MenuItem 
            icon={<LuWarehouse />} 
            command="{actionKey} h"
            asComp={<Link to="/" />}
        >
            Homepage
        </MenuItem>
        <MenuItem icon={<IoAdd />} command="{actionKey} n">Add new</MenuItem>
        <MenuItem icon={<LuAlarmClock />} command="{actionKey} a">Set alarm</MenuItem>
        <MenuItem icon={<LuBattery />} command="{actionKey} b">Battery</MenuItem>
        <MenuItem icon={<LuTrash />} command="{actionKey} d">Delete</MenuItem>
    </MenuContent>
</Menu>

You can control the menu with isOpen, onOpen and onClose props with useControllable hook.

Closed

export function ControlledMenu() {
    const { isOpen, onClose, onOpen } = useControllable();
 
    return (
        <Menu
            isOpen={isOpen}
            onOpen={onOpen}
            onClose={onClose}
        >
            <Text>{isOpen ? "Open" : "Closed"}</Text>
            <MenuTrigger>
                <Button>Open Menu</Button>
            </MenuTrigger>
            <MenuContent>
                <MenuItem
                    icon={<LuWarehouse />} 
                    command="{actionKey} h"
                    asComp={<Link to="/" />}
                >
                    Homepage
                </MenuItem>
                <MenuItem icon={<IoAdd />} command="{actionKey} n">Add new</MenuItem>
                <MenuItem icon={<LuAlarmClock />} command="{actionKey} a">Set alarm</MenuItem>
                <MenuItem icon={<LuBattery />} command="{actionKey} b">Battery</MenuItem>
                <MenuItem icon={<LuTrash />} command="{actionKey} d">Delete</MenuItem>
            </MenuContent>
        </Menu>
    );
}

command props does not provide any logic. You can use useEventListener hook to add logic to the commands.

export function InteractiveMenu() {
    const navigate = useNavigate();
    
    useEventListener("keydown", (event) => {
        if (!event[getActionKeyCode()]) return; // Making sure the ctrl/cmd key is pressed
 
        switch (event.key) {
            case "h": {
                event.preventDefault();
                navigate("/");
                alert("Homepage");
                break;
            }
            case "n": {
                event.preventDefault();
                alert("New");
                break;
            }
            case "a": {
                event.preventDefault();
                alert("Alarm");
                break;
            }
            case "b": {
                event.preventDefault();
                alert("Battery");
                break;
            }
            case "d": {
                event.preventDefault();
                alert("Delete");
                break;
            }
        }
    });
 
    return (
        <Menu>
            <MenuTrigger>
                <Button w={"fit-content"}>Open Menu</Button>
            </MenuTrigger>
            <MenuContent>
                <MenuItem
                    icon={<LuWarehouse />}
                    command="{actionKey} h"
                    asComp={<Link to="/" />}
                >
                    Homepage
                </MenuItem>
                <MenuItem
                    icon={<IoAdd />}
                    command="{actionKey} n"
                >
                    Add new
                </MenuItem>
                <MenuItem
                    icon={<LuAlarmClock />}
                    command="{actionKey} a"
                >
                    Set alarm
                </MenuItem>
                <MenuItem
                    icon={<LuBattery />}
                    command="{actionKey} b"
                >
                    Battery
                </MenuItem>
                <MenuItem
                    icon={<LuTrash />}
                    command="{actionKey} d"
                >
                    Delete
                </MenuItem>
            </MenuContent>
        </Menu>
    );
}