Create your first Slash Command
Slash Commands Overview
What are Slash Commands?
Slash commands are a type of Discord interface that allows users to interact directly with bots by typing commands that begin with a forward slash (/
). Introduced by Discord in late 2020, slash commands have become an integral part of the Discord user experience. They offer a standardized method of sending commands to bots, ensuring that users have a consistent and intuitive way to interact across different servers.
Importance of Slash Commands
Slash commands are crucial for enhancing user engagement and simplifying interactions in Discord. They provide immediate feedback to the user about available commands and how to use them, thanks to the built-in auto-complete feature that guides the user through the command usage process. This not only improves the overall user experience but also reduces the learning curve associated with new bots. Furthermore, slash commands allow for more secure and controlled interactions, as they are processed entirely server-side by Discord, thus reducing the risk of security vulnerabilities associated with traditional text commands.
Implementing Slash Commands (with ban.js)
To define the /ban
command, start by importing necessary elements from the umbrae
library and setting up the command structure with CommandBuilder
. For the example below, we created the command with the path ./commands/[dir]/ban.js
.
Warning
In this path [dir]
represents a mid-level directory situated between the root commands
directory and the specific command file (ban.js
). This structure helps organize commands into categorically relevant directories for better manageability and clarity.
import { CommandBuilder, Permissions} from 'umbrae';
export default CommandBuilder(
{
slash: true,
name: 'ban',
description: 'Ban a member',
permissions: [Permissions.BanMembers, Permissions.ManageMessages],
cooldown: 5,
args: [
{
name: 'user',
type: 'User',
description: 'The user to ban',
required: true
},
{
name: 'reason',
type: 'String',
description: 'The reason for the ban',
choices: [
{
name: 'Spam',
value: 'spam'
},
{
name: 'Harassment',
value: 'harassment'
},
{
name: 'Advertising',
value: 'advertising'
}
],
required: true
}
]
},
async (interaction, app, data) => {
await interaction.deferReply({ ephemeral: true });
const user = interaction.options.getUser('user', true);
const member = interaction.guild.members.cache.get(user.id);
const appMember = interaction.guild.members.cache.get(app.user.id);
const reason = interaction.options.getString('reason', true);
if (appMember.permissions.has(Permissions.BanMembers) && (appMember.roles.highest.position > (member.roles.highest.position as number))
&& member.manageable) {
try {
await member.ban({ reason });
await interaction.editReply({ content: 'Sucefully banned '+` **${user.globalName}** (`+"`"+user.id+"`"+')' });
} catch (e) {
console.error(e);
await interaction.editReply({ content: 'An error occured while banning '+` **${user.globalName}** (`+"`"+user.id+"`"+')' });
}
}
}
)
import { CommandBuilder, Permissions, SlashCommandBuilderOptions } from 'umbrae';
export default CommandBuilder<SlashCommandBuilderOptions>(
{
slash: true,
name: 'ban',
description: 'Ban a member',
permissions: [Permissions.BanMembers, Permissions.ManageMessages],
cooldown: 5,
args: [
{
name: 'user',
type: 'User',
description: 'The user to ban',
required: true
},
{
name: 'reason',
type: 'String',
description: 'The reason for the ban',
choices: [
{
name: 'Spam',
value: 'spam'
},
{
name: 'Harassment',
value: 'harassment'
},
{
name: 'Advertising',
value: 'advertising'
}
],
required: true
}
]
},
async (interaction, app, data) => {
await interaction.deferReply({ ephemeral: true });
const user = interaction.options.getUser('user', true);
const member = interaction.guild?.members.cache.get((user.id as string));
const appMember = interaction.guild?.members.cache.get((app.user?.id as string));
const reason = interaction.options.getString('reason', true);
if (appMember?.permissions.has(Permissions.BanMembers) && (appMember.roles.highest.position > (member?.roles.highest.position as number))
&& member?.manageable) {
try {
await member?.ban({ reason });
await interaction.editReply({ content: 'Sucefully banned '+` **${user.globalName}** (`+"`"+user.id+"`"+')' });
} catch (e) {
console.error(e);
await interaction.editReply({ content: 'An error occured while banning '+` **${user.globalName}** (`+"`"+user.id+"`"+')' });
}
}
}
)
Warning
The option slash
set to true
is required to build a SlashCommand otherwise you are building a MessageCommand.
Key Features of the CommandBuilder
1.0.3
- Simplicity and Clarity: The
CommandBuilder
function simplifies the definition and setup of commands by encapsulating options and logic in a single function call. - Permission Handling: It easily integrates permission checks to ensure that only authorized users can execute sensitive commands like banning.
- Argument Handling: This setup enables the command to handle user inputs efficiently, providing auto-complete options for reasons, and requiring necessary arguments.
CommandBuilderOptions
If you are using TypeScript to build your project, you should opt for SlashCommandBuilderOptions
instead of creating a standard CommandBuilder
function. However, you should also review this section to ensure that you are creating commands correctly.
type Permissions = BitFieldResolvable<keyof typeof PermissionFlagsBits, bigint>;
type ArgType = 'Attachment' | 'User' | 'Channel' | 'Role' | 'Mentionable' | 'String' | 'Integer' | 'Number' | 'Boolean' | 'Subcommand' | 'SubcommandGroup';
interface Choice {
name: string;
value: string | number;
}
interface Arg {
name: string;
description: string;
type: ArgType;
choices?: Choice[];
required?: boolean;
}
interface CommandBuilderOptionsBase {
name: string;
description: string;
cooldown?: number;
permissions: Permissions[];
args?: Arg[];
}
interface SlashCommandBuilderOptions extends CommandBuilderOptionsBase {
slash: true;
}