Context menus allow users to interact with Discord elements (users or messages) by right-clicking on them. They provide quick access to bot functionality directly from the context.
Context menus in djs-core are created using the ContextMenu class. Each context menu file in src/interactions/contexts/ automatically becomes available in Discord.
A user context menu appears when right-clicking on a user:
import { ContextMenu } from "@djs-core/runtime";
import { ApplicationCommandType } from "discord.js";
export default new ContextMenu()
.withType(ApplicationCommandType.User)
.run(async (interaction) => {
const user = interaction.targetUser;
await interaction.reply({
content: `Hello, ${user.username}!`,
});
});
File location: src/interactions/contexts/user/hi.ts
interaction.targetUser and interaction.targetMember.interaction.targetMessage.A message context menu appears when right-clicking on a message:
import { ContextMenu } from "@djs-core/runtime";
import { ApplicationCommandType } from "discord.js";
export default new ContextMenu()
.withType(ApplicationCommandType.Message)
.run(async (interaction) => {
const message = interaction.targetMessage;
// Add a reaction to the message
await message.react("👍");
await interaction.reply({
content: "Message liked!",
ephemeral: true,
});
});
File location: src/interactions/contexts/message/like.ts
Context menus are organized by type in the file structure. The folder structure determines where the context menu appears:
import { ContextMenu } from "@djs-core/runtime";
import { ApplicationCommandType } from "discord.js";
export default new ContextMenu()
.withType(ApplicationCommandType.User)
.run(async (interaction) => {
await interaction.reply(`Hi, ${interaction.targetUser.username}!`);
});
| File Path | Context Menu |
|---|---|
src/interactions/contexts/user/hi.ts | Right-click user → "Hi" |
src/interactions/contexts/user/info.ts | Right-click user → "Info" |
src/interactions/contexts/message/like.ts | Right-click message → "Like" |
src/interactions/contexts/message/report.ts | Right-click message → "Report" |
When using ApplicationCommandType.User, you can access the targeted user:
import { ContextMenu } from "@djs-core/runtime";
import { ApplicationCommandType } from "discord.js";
export default new ContextMenu()
.withType(ApplicationCommandType.User)
.run(async (interaction) => {
const user = interaction.targetUser;
const member = interaction.targetMember; // Guild member if in a server
await interaction.reply({
content: `User: ${user.tag}\nID: ${user.id}`,
});
});
When using ApplicationCommandType.Message, you can access the targeted message:
import { ContextMenu } from "@djs-core/runtime";
import { ApplicationCommandType } from "discord.js";
export default new ContextMenu()
.withType(ApplicationCommandType.Message)
.run(async (interaction) => {
const message = interaction.targetMessage;
const author = message.author;
await interaction.reply({
content: `Message by ${author.tag}: ${message.content}`,
});
});
You can restrict context menus to users with specific permissions:
import { ContextMenu } from "@djs-core/runtime";
import { ApplicationCommandType, PermissionFlagsBits } from "discord.js";
export default new ContextMenu()
.withType(ApplicationCommandType.Message)
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages)
.run(async (interaction) => {
await interaction.targetMessage.delete();
await interaction.reply({
content: "Message deleted!",
ephemeral: true,
});
});
You can control whether context menus are available in DMs:
import { ContextMenu } from "@djs-core/runtime";
import { ApplicationCommandType } from "discord.js";
export default new ContextMenu()
.withType(ApplicationCommandType.User)
.setDMPermission(false) // Only available in servers
.run(async (interaction) => {
await interaction.reply("Server-only context menu!");
});
djs-core provides full TypeScript support for context menus. The interaction type is automatically inferred based on the menu type, giving you autocomplete and type checking:
targetUser and targetMember. For Message menus, you'll have access to targetMessage.import { ContextMenu } from "@djs-core/runtime";
import { ApplicationCommandType } from "discord.js";
export default new ContextMenu()
.withType(ApplicationCommandType.User)
.run(async (interaction) => {
// interaction is typed as UserContextMenuCommandInteraction
// interaction.targetUser is available
// interaction.targetMember is available (in guilds)
const user = interaction.targetUser; // ✅ Type-safe
// const message = interaction.targetMessage; // ❌ Type error
});