Context Menu
Displays a menu at the pointer, triggered by a right click or a long press.
Right-click here
import * as stylex from '@stylexjs/stylex';
import {
ContextMenu,
ContextMenuCheckboxItem,
ContextMenuContent,
ContextMenuItem,
ContextMenuRadioGroup,
ContextMenuRadioItem,
ContextMenuSeparator,
ContextMenuShortcut,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuTrigger,
} from '@/components/ui/context-menu';
import { space, fontSize, stroke, container } from '@/lib/constants.stylex';
import { colors, font, radius } from '@/lib/tokens.stylex';
export default function ContextMenuDemo() {
return (
<ContextMenu>
<ContextMenuTrigger style={styles.trigger}>
Right-click here
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem>
Back
<ContextMenuShortcut>⌘[</ContextMenuShortcut>
</ContextMenuItem>
<ContextMenuItem disabled>
Forward
<ContextMenuShortcut>⌘]</ContextMenuShortcut>
</ContextMenuItem>
<ContextMenuSub>
<ContextMenuSubTrigger>More tools</ContextMenuSubTrigger>
<ContextMenuSubContent>
<ContextMenuItem>Save page…</ContextMenuItem>
<ContextMenuItem>Create shortcut…</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem>Developer tools</ContextMenuItem>
</ContextMenuSubContent>
</ContextMenuSub>
<ContextMenuSeparator />
<ContextMenuCheckboxItem defaultChecked>
Show bookmarks
</ContextMenuCheckboxItem>
<ContextMenuCheckboxItem>Show full URLs</ContextMenuCheckboxItem>
<ContextMenuSeparator />
<ContextMenuRadioGroup defaultValue="pedro">
<ContextMenuRadioItem value="pedro">Pedro Duarte</ContextMenuRadioItem>
<ContextMenuRadioItem value="colm">Colm Tuite</ContextMenuRadioItem>
</ContextMenuRadioGroup>
<ContextMenuSeparator />
<ContextMenuItem variant="destructive">Delete</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
);
}
const styles = stylex.create({
trigger: {
alignItems: 'center',
borderColor: colors.border,
borderRadius: radius.lg,
borderStyle: 'dashed',
borderWidth: stroke.border,
color: colors.foreground,
display: 'flex',
fontFamily: font.sans,
fontSize: fontSize.sm,
height: container.xs,
justifyContent: 'center',
width: container.sm,
paddingInline: space.s4,
textAlign: 'center',
},
});
Install
npx shadcn@latest add @madeui/context-menu
Usage
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
} from '@/components/ui/context-menu';
Composition
<ContextMenu>
<ContextMenuTrigger />
<ContextMenuContent>
<ContextMenuLabel />
<ContextMenuItem />
<ContextMenuCheckboxItem />
<ContextMenuRadioGroup>
<ContextMenuRadioItem />
</ContextMenuRadioGroup>
<ContextMenuSub>
<ContextMenuSubTrigger />
<ContextMenuSubContent />
</ContextMenuSub>
<ContextMenuSeparator />
</ContextMenuContent>
</ContextMenu>
Submenu
Right-click here
import * as stylex from '@stylexjs/stylex';
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuTrigger,
} from '@/components/ui/context-menu';
import { space, fontSize, stroke, container } from '@/lib/constants.stylex';
import { colors, font, radius } from '@/lib/tokens.stylex';
export default function ContextMenuSubmenu() {
return (
<ContextMenu>
<ContextMenuTrigger style={styles.trigger}>
Right-click here
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem>Save page…</ContextMenuItem>
<ContextMenuSub>
<ContextMenuSubTrigger>More tools</ContextMenuSubTrigger>
<ContextMenuSubContent>
<ContextMenuItem>Save page as…</ContextMenuItem>
<ContextMenuItem>Create shortcut…</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem>Developer tools</ContextMenuItem>
</ContextMenuSubContent>
</ContextMenuSub>
</ContextMenuContent>
</ContextMenu>
);
}
const styles = stylex.create({
trigger: {
alignItems: 'center',
borderColor: colors.border,
borderRadius: radius.lg,
borderStyle: 'dashed',
borderWidth: stroke.border,
color: colors.foreground,
display: 'flex',
fontFamily: font.sans,
fontSize: fontSize.sm,
height: container.xs,
justifyContent: 'center',
width: container.sm,
paddingInline: space.s4,
textAlign: 'center',
},
});
Checkbox items
Right-click here
import * as stylex from '@stylexjs/stylex';
import {
ContextMenu,
ContextMenuCheckboxItem,
ContextMenuContent,
ContextMenuGroup,
ContextMenuLabel,
ContextMenuTrigger,
} from '@/components/ui/context-menu';
import { space, fontSize, stroke, container } from '@/lib/constants.stylex';
import { colors, font, radius } from '@/lib/tokens.stylex';
export default function ContextMenuCheckboxes() {
return (
<ContextMenu>
<ContextMenuTrigger style={styles.trigger}>
Right-click here
</ContextMenuTrigger>
<ContextMenuContent>
{/* Menu labels are Base UI GroupLabels — they must live inside a
Group or RadioGroup. */}
<ContextMenuGroup>
<ContextMenuLabel>Appearance</ContextMenuLabel>
<ContextMenuCheckboxItem defaultChecked>
Show bookmarks bar
</ContextMenuCheckboxItem>
<ContextMenuCheckboxItem>Show full URLs</ContextMenuCheckboxItem>
</ContextMenuGroup>
</ContextMenuContent>
</ContextMenu>
);
}
const styles = stylex.create({
trigger: {
alignItems: 'center',
borderColor: colors.border,
borderRadius: radius.lg,
borderStyle: 'dashed',
borderWidth: stroke.border,
color: colors.foreground,
display: 'flex',
fontFamily: font.sans,
fontSize: fontSize.sm,
height: container.xs,
justifyContent: 'center',
width: container.sm,
paddingInline: space.s4,
textAlign: 'center',
},
});
Radio group
Right-click here
import * as stylex from '@stylexjs/stylex';
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuRadioGroup,
ContextMenuRadioItem,
ContextMenuSeparator,
ContextMenuTrigger,
} from '@/components/ui/context-menu';
import { space, fontSize, stroke, container } from '@/lib/constants.stylex';
import { colors, font, radius } from '@/lib/tokens.stylex';
export default function ContextMenuRadio() {
return (
<ContextMenu>
<ContextMenuTrigger style={styles.trigger}>
Right-click here
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuRadioGroup defaultValue="pedro">
<ContextMenuRadioItem value="pedro">Pedro Duarte</ContextMenuRadioItem>
<ContextMenuRadioItem value="colm">Colm Tuite</ContextMenuRadioItem>
</ContextMenuRadioGroup>
<ContextMenuSeparator />
{/* A radio item outside its RadioGroup has no context — plain item. */}
<ContextMenuItem disabled>Add new user…</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
);
}
const styles = stylex.create({
trigger: {
alignItems: 'center',
borderColor: colors.border,
borderRadius: radius.lg,
borderStyle: 'dashed',
borderWidth: stroke.border,
color: colors.foreground,
display: 'flex',
fontFamily: font.sans,
fontSize: fontSize.sm,
height: container.xs,
justifyContent: 'center',
width: container.sm,
paddingInline: space.s4,
textAlign: 'center',
},
});
Destructive item
Right-click here
import * as stylex from '@stylexjs/stylex';
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuTrigger,
} from '@/components/ui/context-menu';
import { space, fontSize, stroke, container } from '@/lib/constants.stylex';
import { colors, font, radius } from '@/lib/tokens.stylex';
export default function ContextMenuDestructive() {
return (
<ContextMenu>
<ContextMenuTrigger style={styles.trigger}>
Right-click here
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem>Rename</ContextMenuItem>
<ContextMenuItem>Duplicate</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem variant="destructive">Delete</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
);
}
const styles = stylex.create({
trigger: {
alignItems: 'center',
borderColor: colors.border,
borderRadius: radius.lg,
borderStyle: 'dashed',
borderWidth: stroke.border,
color: colors.foreground,
display: 'flex',
fontFamily: font.sans,
fontSize: fontSize.sm,
height: container.xs,
justifyContent: 'center',
width: container.sm,
paddingInline: space.s4,
textAlign: 'center',
},
});
API reference
Built on Base UI Context Menu. The tables below cover the props this library adds or changes — every other prop is forwarded; see the Base UI Context Menu API reference.
ContextMenuContent
| Prop | Type | Default | Description |
|---|---|---|---|
side |
'top' | 'right' | 'bottom' | 'left' |
'right' |
|
sideOffset |
number |
0 |
|
align |
'start' | 'center' | 'end' |
'start' |
|
alignOffset |
number |
4 |
|
style |
StyleXStyles |
— | StyleX styles merged last — always win over the component’s own styles. |
ContextMenuItem
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
'default' | 'destructive' |
'default' |
|
inset |
boolean |
— | Indents to align with checkbox/radio item labels. |
ContextMenuShortcut renders right-aligned muted shortcut text. ContextMenuSubContent opens to the right with content-based width.