Registering Context Commands
Context Menu Commands are another kind of application command. They show up, as the name implies, in the context menus of either messages or users when you right click them.
Message Context Menu | User Context Menu |
---|---|
![]() | ![]() |
There's a lot of overlap with the previous Registering Chat Input Commands section, including important information that isn't repeated here, so please skim that first!
To register a Message or User Context Command, implement the registerApplicationCommands
method for the
Command
class. The method's parameter will be the command's pre-defined
ApplicationCommandRegistry
, on which you can call registerContextMenuCommand
to register your
application command.
registerContextMenuCommand
This method is responsible for describing how a Message or User Context Menu Command will be registered. It takes two parameters:
-
command
: This is the Chat Input Command data that the registry will register with Discord. This can be a@discordjs/builders
ContextMenuCommandBuilder
↗️, a method that returns aContextMenuCommandBuilder
↗️, or adiscord.js
ApplicationCommandData
↗️ object. -
options
: These are optional options that change how the Context Menu Command will be registered. These are the same as the ones forregisterChatInputCommand
, and are already discussed in Chat Input Command Registry Options from the previous section.
How to register a Message Context Menu Command
Register a Message Context Menu Command by calling the registerContextMenuCommand
method on the registry with
the type specified in .setType()
, this looks like:
- CommonJS
- ESM
- TypeScript
const { Command } = require('@sapphire/framework');
const { ApplicationCommandType } = require('discord.js');
class SlashCommand extends Command {
constructor(context, options) {
super(context, {
...options,
description: 'Delete message and ban author.'
});
}
registerApplicationCommands(registry) {
registry.registerContextMenuCommand((builder) =>
builder //
.setName(this.name)
.setType(ApplicationCommandType.Message)
);
}
contextMenuRun(interaction) {
// ...
}
}
module.exports = {
SlashCommand
};
import { Command } from '@sapphire/framework';
import { ApplicationCommandType } from 'discord.js';
export class SlashCommand extends Command {
constructor(context, options) {
super(context, {
...options,
description: 'Delete message and ban author.'
});
}
registerApplicationCommands(registry) {
registry.registerContextMenuCommand((builder) =>
builder //
.setName(this.name)
.setType(ApplicationCommandType.Message)
);
}
contextMenuRun(interaction) {
// ...
}
}
import { Command } from '@sapphire/framework';
import { ApplicationCommandType } from 'discord.js';
export class SlashCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
super(context, {
...options,
description: 'Delete message and ban author.'
});
}
public override registerApplicationCommands(registry: Command.Registry) {
registry.registerContextMenuCommand((builder) =>
builder //
.setName(this.name)
.setType(ApplicationCommandType.Message)
);
}
public override contextMenuRun(interaction: Command.ContextMenuCommandInteraction) {
// ...
}
}
It should be noted that unlike Registering Chat Input Commands, it's not possible for
Context Menu Commands to hold a description. This is why we recommend using the ContextMenuCommandBuilder
↗️ here for input verification instead of alternatives such as writing the
ApplicationCommandData
↗️ JSON yourself.
The registerContextMenuCommand
method, similar to the registerChatInputCommand
method in the
previous section, takes in a second options parameter. Please see Chat Input Command Registry Options, since
there are important details not repeated here.
How to register a User Context Menu Command
Registering a User Context Menu is done in the same way, with the only difference being a different type specified in
.setType()
:
- CommonJS
- ESM
- TypeScript
const { Command } = require('@sapphire/framework');
const { ApplicationCommandType } = require('discord.js');
class SlashCommand extends Command {
constructor(context, options) {
super(context, {
...options,
description: 'Ban user.'
});
}
registerApplicationCommands(registry) {
registry.registerContextMenuCommand((builder) =>
builder //
.setName(this.name)
.setType(ApplicationCommandType.User)
);
}
contextMenuRun(interaction) {
// ...
}
}
module.exports = {
SlashCommand
};
import { Command } from '@sapphire/framework';
import { ApplicationCommandType } from 'discord.js';
export class SlashCommand extends Command {
constructor(context, options) {
super(context, {
...options,
description: 'Ban user.'
});
}
registerApplicationCommands(registry) {
registry.registerContextMenuCommand((builder) =>
builder //
.setName(this.name)
.setType(ApplicationCommandType.User)
);
}
contextMenuRun(interaction) {
// ...
}
}
import { Command } from '@sapphire/framework';
import { ApplicationCommandType } from 'discord.js';
export class SlashCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
super(context, {
...options,
description: 'Ban user.'
});
}
public override registerApplicationCommands(registry: Command.Registry) {
registry.registerContextMenuCommand((builder) =>
builder //
.setName(this.name)
.setType(ApplicationCommandType.User)
);
}
public override contextMenuRun(interaction: Command.ContextMenuCommandInteraction) {
// ...
}
}
Just like the Message Context Menu Command, the registerContextMenuCommand
method takes in a second options
parameter. Please see Chat Input Command Registry Options, since there are important details not repeated here.
Implementing a Context Menu Command
Now that we've covered registering a Message or User Context Menu Command, the last step is to implement the
contextMenuRun
method for the Command
class so your bot can respond! The example here is the second User
Context Menu Command started above:
- CommonJS
- ESM
- TypeScript
const { Command } = require('@sapphire/framework');
const { ApplicationCommandType, userMention, GuildMember } = require('discord.js');
class SlashCommand extends Command {
constructor(context, options) {
super(context, {
...options,
description: 'Ban user.'
});
}
registerApplicationCommands(registry) {
registry.registerContextMenuCommand((builder) =>
builder //
.setName(this.name)
.setType(ApplicationCommandType.User)
);
}
async contextMenuRun(interaction) {
// Use isUserContextMenu() to ensure this command was executed as a User Context Menu Command
if (interaction.isUserContextMenuCommand() && interaction.targetMember instanceof GuildMember) {
await interaction.targetMember.ban({
days: 8,
reason: 'Banned for for breaking the rules.'
});
const userToGreetMention = userMention(interaction.targetMember.id);
return interaction.reply({
content: `${userToGreetMention} has been successfully banned`,
allowedMentions: {
users: [interaction.targetMember.id]
}
});
}
}
}
module.exports = {
SlashCommand
};
import { Command } from '@sapphire/framework';
import { ApplicationCommandType, userMention, GuildMember } from 'discord.js';
export class SlashCommand extends Command {
constructor(context, options) {
super(context, {
...options,
description: 'Ban user.'
});
}
registerApplicationCommands(registry) {
registry.registerContextMenuCommand((builder) =>
builder //
.setName(this.name)
.setType(ApplicationCommandType.User)
);
}
async contextMenuRun(interaction) {
// Use isUserContextMenu() to ensure this command was executed as a User Context Menu Command
if (interaction.isUserContextMenuCommand() && interaction.targetMember instanceof GuildMember) {
await interaction.targetMember.ban({
days: 8,
reason: 'Banned for for breaking the rules.'
});
const userToGreetMention = userMention(interaction.targetMember.id);
return interaction.reply({
content: `${userToGreetMention} has been successfully banned`,
allowedMentions: {
users: [interaction.targetMember.id]
}
});
}
}
}
import { Command } from '@sapphire/framework';
import { ApplicationCommandType, userMention, GuildMember } from 'discord.js';
export class SlashCommand extends Command {
public constructor(context: Command.LoaderContext, options: Command.Options) {
super(context, {
...options,
description: 'Ban user.'
});
}
public override registerApplicationCommands(registry: Command.Registry) {
registry.registerContextMenuCommand((builder) =>
builder //
.setName(this.name)
.setType(ApplicationCommandType.User)
);
}
public override async contextMenuRun(interaction: Command.ContextMenuCommandInteraction) {
// Use isUserContextMenu() to ensure this command was executed as a User Context Menu Command
if (interaction.isUserContextMenuCommand() && interaction.targetMember instanceof GuildMember) {
await interaction.targetMember.ban({
days: 8,
reason: 'Banned for for breaking the rules.'
});
const userToGreetMention = userMention(interaction.targetMember.id);
return interaction.reply({
content: `${userToGreetMention} has been successfully banned`,
allowedMentions: {
users: [interaction.targetMember.id]
}
});
}
}
}
Since contextMenuRun
runs both kind of context commands, we recommend using either isMessageContextMenu()
or
isUserContextMenu()
to ensure the correct kind of context menu application command is executing your command.