ComponentsDropdownMenu

DropdownMenu

Display a dropdown menu.

Documentation

Usage

Use the DropdownMenu, DropdownMenuTrigger, and DropdownMenuContent components to build out menus.

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@optiaxiom/react";
import { IconLogout, IconUser } from "@tabler/icons-react";
 
export function App() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger>Open</DropdownMenuTrigger>
 
      <DropdownMenuContent>
        <DropdownMenuLabel>My Account</DropdownMenuLabel>
        <DropdownMenuItem addonBefore={<IconUser />}>
          View Profile
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem addonBefore={<IconLogout />}>Logout</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

Controlled

Use the open and defaultOpen props to toggle between controlled and uncontrolled usage. And combine it with onOpenChange to listen for changes to the state.

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
  Flex,
  Switch,
} from "@optiaxiom/react";
import { IconLogout, IconUser } from "@tabler/icons-react";
import { useState } from "react";
 
export function App() {
  const [keepOpen, setKeepOpen] = useState(false);
  const [open, setOpen] = useState(false);
 
  return (
    <Flex flexDirection="row">
      <Switch onCheckedChange={setKeepOpen}>Keep menu open</Switch>
 
      <DropdownMenu
        modal={false}
        onOpenChange={(flag) => setOpen(flag || keepOpen)}
        open={open}
      >
        <DropdownMenuTrigger>Open</DropdownMenuTrigger>
 
        <DropdownMenuContent>
          <DropdownMenuLabel>My Account</DropdownMenuLabel>
          <DropdownMenuItem addonBefore={<IconUser />}>
            View Profile
          </DropdownMenuItem>
          <DropdownMenuSeparator />
          <DropdownMenuItem addonBefore={<IconLogout />}>
            Logout
          </DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>
    </Flex>
  );
}

Non modal usage

By default scrolling and interactions with outside elements is disabled when menu is open. Set modal prop to false in order to render a non-modal dropdown.

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@optiaxiom/react";
import { IconLogout, IconUser } from "@tabler/icons-react";
 
export function App() {
  return (
    <DropdownMenu modal={false}>
      <DropdownMenuTrigger>Open</DropdownMenuTrigger>
 
      <DropdownMenuContent>
        <DropdownMenuLabel>My Account</DropdownMenuLabel>
        <DropdownMenuItem addonBefore={<IconUser />}>
          View Profile
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem addonBefore={<IconLogout />}>Logout</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

Trigger

Customize trigger

By default we use the Button component for the menu trigger which accepts all of the existing button props.

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@optiaxiom/react";
import { IconDots, IconLogout, IconUser } from "@tabler/icons-react";
 
export function App() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger
        appearance="subtle"
        aria-label="My Account"
        icon={<IconDots />}
      />
 
      <DropdownMenuContent>
        <DropdownMenuLabel>My Account</DropdownMenuLabel>
        <DropdownMenuItem addonBefore={<IconUser />}>
          View Profile
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem addonBefore={<IconLogout />}>Logout</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

Composition

We can also completely change the trigger by using asChild and passing our own component.

import {
  Avatar,
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@optiaxiom/react";
import { IconLogout, IconUser } from "@tabler/icons-react";
 
export function App() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Avatar asChild colorScheme="brand">
          <button>JD</button>
        </Avatar>
      </DropdownMenuTrigger>
 
      <DropdownMenuContent>
        <DropdownMenuLabel>My Account</DropdownMenuLabel>
        <DropdownMenuItem addonBefore={<IconUser />}>
          View Profile
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem addonBefore={<IconLogout />}>Logout</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

Content

Menu position

Use the align and side props on DropdownMenuContent to change the default position of the dropdown.

import type { ComponentPropsWithRef } from "react";
 
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@optiaxiom/react";
import { IconLogout, IconUser } from "@tabler/icons-react";
 
export function App({
  align,
  side,
}: Pick<ComponentPropsWithRef<typeof DropdownMenuContent>, "align" | "side">) {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger>Open</DropdownMenuTrigger>
 
      <DropdownMenuContent align={align} side={side}>
        <DropdownMenuLabel>My Account</DropdownMenuLabel>
        <DropdownMenuItem addonBefore={<IconUser />}>
          View Profile
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem addonBefore={<IconLogout />}>Logout</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

Item

Appearance

Use the colorScheme prop to control the appearance of items.

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@optiaxiom/react";
import { IconPencil, IconTrash } from "@tabler/icons-react";
 
export function App() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger>Open</DropdownMenuTrigger>
 
      <DropdownMenuContent>
        <DropdownMenuItem addonBefore={<IconPencil />}>Edit</DropdownMenuItem>
        <DropdownMenuItem addonBefore={<IconTrash />} colorScheme="danger">
          Delete
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

Description

Use the description prop to add secondary text to items.

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@optiaxiom/react";
 
export function App() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger>Actions</DropdownMenuTrigger>
 
      <DropdownMenuContent>
        <DropdownMenuItem description="Create a new task">
          New task
        </DropdownMenuItem>
        <DropdownMenuItem description="Copy this task">
          Copy task
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem colorScheme="danger">Delete task</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

Disabled items

Use the disabled prop on menu items to disable them.

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@optiaxiom/react";
import { IconLogout, IconUser, IconUsers } from "@tabler/icons-react";
 
export function App() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger>Open</DropdownMenuTrigger>
 
      <DropdownMenuContent>
        <DropdownMenuLabel>My Account</DropdownMenuLabel>
        <DropdownMenuItem addonBefore={<IconUser />}>
          View Profile
        </DropdownMenuItem>
        <DropdownMenuItem addonBefore={<IconUsers />} disabled>
          Team Management
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem addonBefore={<IconLogout />}>Logout</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

Label

Use the DropdownMenuLabel component to render a read-only label.

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@optiaxiom/react";
import { IconLogout, IconUser } from "@tabler/icons-react";
 
export function App() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger>Open</DropdownMenuTrigger>
 
      <DropdownMenuContent>
        <DropdownMenuLabel>My Account</DropdownMenuLabel>
        <DropdownMenuItem addonBefore={<IconUser />}>
          View Profile
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem addonBefore={<IconLogout />}>Logout</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

Selection

Use the onSelect prop to handle selection of items.

Last selected item:

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
  Flex,
  Text,
} from "@optiaxiom/react";
import { IconLogout, IconUser } from "@tabler/icons-react";
import { useState } from "react";
 
export function App() {
  const [selected, setSelected] = useState("");
 
  return (
    <Flex flexDirection="row">
      <DropdownMenu>
        <DropdownMenuTrigger>Open</DropdownMenuTrigger>
 
        <DropdownMenuContent>
          <DropdownMenuLabel>My Account</DropdownMenuLabel>
          <DropdownMenuItem
            addonBefore={<IconUser />}
            onSelect={() => setSelected("view")}
          >
            View Profile
          </DropdownMenuItem>
          <DropdownMenuSeparator />
          <DropdownMenuItem
            addonBefore={<IconLogout />}
            onSelect={() => setSelected("logout")}
          >
            Logout
          </DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>
 
      <Text>Last selected item: {selected}</Text>
    </Flex>
  );
}

Left and right addons

Use the addonBefore and addonAfter prop to add icons, text, or any other element to the start or end of the menu items.

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
  Kbd,
} from "@optiaxiom/react";
import { IconLogout, IconSettings, IconUser } from "@tabler/icons-react";
 
export function App() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger>Open</DropdownMenuTrigger>
 
      <DropdownMenuContent>
        <DropdownMenuLabel>My Account</DropdownMenuLabel>
        <DropdownMenuItem
          addonAfter={
            <Kbd keys={["option", "shift"]} variant="subtle">
              P
            </Kbd>
          }
          addonBefore={<IconSettings />}
        >
          Preferences
        </DropdownMenuItem>
        <DropdownMenuItem addonBefore={<IconUser />}>
          View Profile
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem
          addonAfter={
            <Kbd keys={["option", "shift"]} variant="subtle">
              Q
            </Kbd>
          }
          addonBefore={<IconLogout />}
        >
          Logout
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

Props

DropdownMenu

Name

Type

defaultOpen

false | true

dir

"ltr" | "rtl"

modal

false | true

onOpenChange

(open: boolean) => void

open

false | true

DropdownMenuContent

Supports all Box props in addition to its own.

Name

Type

align

"center" | "end" | "start" = "start"

alignOffset

number

arrowPadding

number

asChild

false | true

avoidCollisions

false | true

collisionBoundary

Element | Element[]

collisionPadding

number | Partial<Record<"bottom" | "left" | "right" | "top", number>>

forceMount

true

Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries.

hideWhenDetached

false | true

loop

false | true

Whether keyboard navigation should loop around @defaultValue false

onCloseAutoFocus

(event: Event) => void

Event handler called when auto-focusing on close. Can be prevented.

onEscapeKeyDown

(event: KeyboardEvent) => void

onFocusOutside

(event: FocusOutsideEvent) => void

onInteractOutside

(event: FocusOutsideEvent | PointerDownOutsideEvent) => void

onPointerDownOutside

(event: PointerDownOutsideEvent) => void

side

"bottom" | "left" | "right" | "top"

sideOffset

number = "2"

sticky

"always" | "partial"

updatePositionStrategy

"always" | "optimized"

DropdownMenuItem

Supports all Box props in addition to its own.

Name

Type

asChild

false | true

disabled

false | true

onSelect

(event: Event) => void

textValue

string

DropdownMenuLabel

Supports all Box props in addition to its own.

Name

Type

asChild

false | true

DropdownMenuSeparator

Supports all Box props in addition to its own.

Name

Type

asChild

false | true

DropdownMenuTrigger

Supports all Box props in addition to its own.

Name

Type

asChild

false | true

Changelog

0.1.0

  • Added component

Copyright 2024 © Optimizely.