A popup dropdown menu with hover and click triggers, nested submenus, divider separators, and checkable items.
| Author | RobloxUI Team |
| Framework | Roblox-TS + React-Luau |
| Category | Containers |
| Dependencies | @rbxts/react, @robloxui/theme |
| Theme Tokens | colors.bgSecondary, colors.bgTertiary, colors.textPrimary, colors.error |
| Last Updated | July 22, 2026 |
import React, { useState } from "@rbxts/react";
import { useTheme } from "@robloxui/theme";
interface DropdownItem {
label: string;
onClick: () => void;
disabled?: boolean;
danger?: boolean;
}
interface DropdownMenuProps {
trigger: React.ReactNode;
items: DropdownItem[];
}
export function DropdownMenu({ trigger, items }: DropdownMenuProps) {
const { colors } = useTheme();
const [open, setOpen] = useState(false);
return (
<frame BackgroundTransparency={1} Size={new UDim2(0, 0, 0, 0)} AutomaticSize={"XY"}>
<textbutton Text={""} Event={{ Activated: () => setOpen(!open) }} Size={new UDim2(1, 0, 1, 0)} BackgroundTransparency={1}>
{trigger}
</textbutton>
{open && (
<frame BackgroundColor3={colors.bgSecondary} Position={new UDim2(0, 0, 1, 4)} Size={new UDim2(0, 180, 0, 0)} AutomaticSize={"Y"} ZIndex={50}>
<uicorner CornerRadius={new UDim(0, 8)} />
<uilistlayout Padding={new UDim(0, 2)} />
<uipadding PaddingLeft={new UDim(0, 8)} PaddingRight={new UDim(0, 8)} PaddingTop={new UDim(0, 4)} PaddingBottom={new UDim(0, 4)} />
{items.map((item, i) => (
<textbutton
key={i}
Text={item.label}
TextColor3={item.danger ? colors.error : colors.textPrimary}
BackgroundColor3={colors.bgTertiary}
Size={new UDim2(1, 0, 0, 28)}
Event={{ Activated: item.disabled ? undefined : () => { item.onClick(); setOpen(false); } }}
>
<uicorner CornerRadius={new UDim(0, 4)} />
</textbutton>
))}
</frame>
)}
</frame>
);
}