Skip to content

Menu

Displays a menu to the user—such as a set of actions or functions—triggered by a button.

Features

  • ✅ Can be controlled or uncontrolled.

Installation

bash
npm i @morpheme/primitives
npm i @morpheme/primitives

Usage

Basic Example

vue
<script setup lang="ts">
import {Menu, MenuButton, MenuItems, MenuItem} from '@morpheme/primitives';
import {ChevronDownIcon} from '@morphemeicons/vue/untitled';
</script>

<template>
  <Menu>
    <MenuButton
      v-slot="{open}"
      class="inline-flex gap-2 items-center relative text-sm"
    >
      <span>Account</span>
      <ChevronDownIcon
        class="w-5 h-5 transform transition-transform duration-200"
        :class="{
          'rotate-180': open,
        }"
      />
    </MenuButton>
    <MenuItems class="absolute w-56 bg-white p-2 border rounded-lg shadow-md">
      <MenuItem
        class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
        v-slot="{active}"
      >
        <a :class="{'bg-blue-500': active}" href="/account-settings">
          Account settings
        </a>
      </MenuItem>
      <MenuItem
        class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
        v-slot="{active}"
      >
        <a :class="{'bg-blue-500': active}" href="/account-settings">
          Documentation
        </a>
      </MenuItem>
      <MenuItem
        as="button"
        class="text-sm text-left w-full px-3 py-2 rounded-lg disabled:cursor-not-allowed disabled:text-gray-400 hover:not:disabled:bg-gray-200"
        disabled
      >
        <span class="opacity-75">Invite a friend (coming soon!)</span>
      </MenuItem>
    </MenuItems>
  </Menu>
</template>
<script setup lang="ts">
import {Menu, MenuButton, MenuItems, MenuItem} from '@morpheme/primitives';
import {ChevronDownIcon} from '@morphemeicons/vue/untitled';
</script>

<template>
  <Menu>
    <MenuButton
      v-slot="{open}"
      class="inline-flex gap-2 items-center relative text-sm"
    >
      <span>Account</span>
      <ChevronDownIcon
        class="w-5 h-5 transform transition-transform duration-200"
        :class="{
          'rotate-180': open,
        }"
      />
    </MenuButton>
    <MenuItems class="absolute w-56 bg-white p-2 border rounded-lg shadow-md">
      <MenuItem
        class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
        v-slot="{active}"
      >
        <a :class="{'bg-blue-500': active}" href="/account-settings">
          Account settings
        </a>
      </MenuItem>
      <MenuItem
        class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
        v-slot="{active}"
      >
        <a :class="{'bg-blue-500': active}" href="/account-settings">
          Documentation
        </a>
      </MenuItem>
      <MenuItem
        as="button"
        class="text-sm text-left w-full px-3 py-2 rounded-lg disabled:cursor-not-allowed disabled:text-gray-400 hover:not:disabled:bg-gray-200"
        disabled
      >
        <span class="opacity-75">Invite a friend (coming soon!)</span>
      </MenuItem>
    </MenuItems>
  </Menu>
</template>

Multi Level

vue
<script setup lang="ts">
import {Menu, MenuButton, MenuItems, MenuItem} from '@morpheme/primitives';
import {ChevronDownIcon} from '@morphemeicons/vue/untitled';
</script>

<template>
  <Menu>
    <MenuButton
      v-slot="{open}"
      class="inline-flex gap-2 items-center relative text-sm"
    >
      <span>Account</span>
      <ChevronDownIcon
        class="w-5 h-5 transform transition-transform duration-200"
        :class="{
          'rotate-180': open,
        }"
      />
    </MenuButton>
    <MenuItems class="absolute w-56 bg-white p-2 border rounded-lg shadow-md">
      <MenuItem
        class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
        v-slot="{active}"
      >
        <a :class="{'bg-blue-500': active}" href="/account-settings">
          Account settings
        </a>
      </MenuItem>
      <MenuItem
        class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
        v-slot="{active}"
      >
        <a :class="{'bg-blue-500': active}" href="/account-settings">
          Documentation
        </a>
      </MenuItem>
      <MenuItem
        as="button"
        class="text-sm text-left w-full px-3 py-2 rounded-lg disabled:cursor-not-allowed disabled:text-gray-400 hover:not:disabled:bg-gray-200"
        disabled
      >
        <span class="opacity-75">Invite a friend (coming soon!)</span>
      </MenuItem>

      <Menu class="relative">
        <MenuButton
          v-slot="{open}"
          class="flex gap-4 justify-between items-center text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
        >
          <span>Preference</span>
          <ChevronDownIcon
            class="w-5 h-5 transform transition-transform duration-200 -rotate-90"
            :class="{
              'rotate-180': open,
            }"
          />
        </MenuButton>
        <MenuItems
          class="absolute top-0 left-full w-56 bg-white p-2 border rounded-lg shadow-md"
        >
          <MenuItem
            class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
            v-slot="{active}"
          >
            <button type="button" :class="{'bg-blue-500': active}">
              System
            </button>
          </MenuItem>
          <MenuItem
            class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
            v-slot="{active}"
          >
            <button type="button" :class="{'bg-blue-500': active}">
              Light
            </button>
          </MenuItem>
          <MenuItem
            class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
            v-slot="{active}"
          >
            <button type="button" :class="{'bg-blue-500': active}">Dark</button>
          </MenuItem>
        </MenuItems>
      </Menu>
    </MenuItems>
  </Menu>
</template>
<script setup lang="ts">
import {Menu, MenuButton, MenuItems, MenuItem} from '@morpheme/primitives';
import {ChevronDownIcon} from '@morphemeicons/vue/untitled';
</script>

<template>
  <Menu>
    <MenuButton
      v-slot="{open}"
      class="inline-flex gap-2 items-center relative text-sm"
    >
      <span>Account</span>
      <ChevronDownIcon
        class="w-5 h-5 transform transition-transform duration-200"
        :class="{
          'rotate-180': open,
        }"
      />
    </MenuButton>
    <MenuItems class="absolute w-56 bg-white p-2 border rounded-lg shadow-md">
      <MenuItem
        class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
        v-slot="{active}"
      >
        <a :class="{'bg-blue-500': active}" href="/account-settings">
          Account settings
        </a>
      </MenuItem>
      <MenuItem
        class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
        v-slot="{active}"
      >
        <a :class="{'bg-blue-500': active}" href="/account-settings">
          Documentation
        </a>
      </MenuItem>
      <MenuItem
        as="button"
        class="text-sm text-left w-full px-3 py-2 rounded-lg disabled:cursor-not-allowed disabled:text-gray-400 hover:not:disabled:bg-gray-200"
        disabled
      >
        <span class="opacity-75">Invite a friend (coming soon!)</span>
      </MenuItem>

      <Menu class="relative">
        <MenuButton
          v-slot="{open}"
          class="flex gap-4 justify-between items-center text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
        >
          <span>Preference</span>
          <ChevronDownIcon
            class="w-5 h-5 transform transition-transform duration-200 -rotate-90"
            :class="{
              'rotate-180': open,
            }"
          />
        </MenuButton>
        <MenuItems
          class="absolute top-0 left-full w-56 bg-white p-2 border rounded-lg shadow-md"
        >
          <MenuItem
            class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
            v-slot="{active}"
          >
            <button type="button" :class="{'bg-blue-500': active}">
              System
            </button>
          </MenuItem>
          <MenuItem
            class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
            v-slot="{active}"
          >
            <button type="button" :class="{'bg-blue-500': active}">
              Light
            </button>
          </MenuItem>
          <MenuItem
            class="text-sm text-left w-full px-3 py-2 rounded-lg hover:bg-gray-200"
            v-slot="{active}"
          >
            <button type="button" :class="{'bg-blue-500': active}">Dark</button>
          </MenuItem>
        </MenuItems>
      </Menu>
    </MenuItems>
  </Menu>
</template>