Slash commands are the primary way users interact with your Discord bot. They appear in Discord's command menu and can accept various types of options.
src/interactions/commands/. The command name is derived from the file path, so src/interactions/commands/ping.ts becomes /ping.Commands in djs-core are created using the Command class. Each command file in src/interactions/commands/ automatically becomes a slash command.
Here's a simple ping command:
import { Command } from "@djs-core/runtime";
export default new Command()
.setDescription("Ping the bot")
.run(async (interaction) => {
await interaction.reply("Pong!");
});
The command name is automatically derived from the file path:
| File Path | Command Name |
|---|---|
src/interactions/commands/ping.ts | /ping |
src/interactions/commands/admin/kick.ts | /admin kick |
src/interactions/commands/shop/buy.ts | /shop buy |
src/interactions/commands/admin/moderation/ban.ts | /admin moderation ban |
Commands can accept various types of options to collect user input. Each option type serves a specific purpose:
import { Command } from "@djs-core/runtime";
import { MessageFlags } from "discord.js";
export default new Command()
.setDescription("A command with options")
.addStringOption((option) =>
option
.setName("text")
.setDescription("Enter some text")
.setRequired(true),
)
.run(async (interaction) => {
const text = interaction.options.getString("text");
await interaction.reply(`You entered: ${text}`);
});
djs-core supports all Discord.js option types. Here are examples for each:
export default new Command()
.setDescription("Set a number")
.addIntegerOption((option) =>
option
.setName("count")
.setDescription("Enter a number")
.setRequired(true)
.setMinValue(1)
.setMaxValue(100),
)
.run(async (interaction) => {
const count = interaction.options.getInteger("count");
await interaction.reply(`You entered: ${count}`);
});
export default new Command()
.setDescription("Get user info")
.addUserOption((option) =>
option
.setName("user")
.setDescription("The user to get info about")
.setRequired(true),
)
.run(async (interaction) => {
const user = interaction.options.getUser("user");
await interaction.reply(`User: ${user?.username} (${user?.id})`);
});
export default new Command()
.setDescription("Configure channel")
.addChannelOption((option) =>
option
.setName("channel")
.setDescription("The channel to configure")
.setRequired(true),
)
.run(async (interaction) => {
const channel = interaction.options.getChannel("channel");
await interaction.reply(`Configured: ${channel?.name}`);
});
export default new Command()
.setDescription("Toggle setting")
.addBooleanOption((option) =>
option
.setName("enabled")
.setDescription("Enable or disable")
.setRequired(true),
)
.run(async (interaction) => {
const enabled = interaction.options.getBoolean("enabled");
await interaction.reply(`Setting is ${enabled ? "enabled" : "disabled"}`);
});
You can add multiple options to a single command:
import { Command } from "@djs-core/runtime";
export default new Command()
.setDescription("Send a message to a user")
.addUserOption((option) =>
option
.setName("user")
.setDescription("The user to message")
.setRequired(true),
)
.addStringOption((option) =>
option
.setName("message")
.setDescription("The message to send")
.setRequired(true),
)
.run(async (interaction) => {
const user = interaction.options.getUser("user");
const message = interaction.options.getString("message");
await interaction.reply({
content: `Sending "${message}" to ${user?.username}`,
});
});
Commands can provide autocomplete suggestions for string, integer, and number options. This improves user experience by showing relevant options as they type.
import { Command } from "@djs-core/runtime";
export default new Command()
.setDescription("Search for something")
.addStringOption((option) =>
option
.setName("query")
.setDescription("Search query")
.setRequired(true)
.setAutocomplete(true)
)
.run(async (interaction) => {
const query = interaction.options.getString("query");
await interaction.reply(`You searched for: ${query}`);
})
.runAutocomplete(async (interaction) => {
const focusedValue = interaction.options.getFocused();
// Filter suggestions based on user input
const choices = ["apple", "banana", "cherry"].filter((choice) =>
choice.startsWith(focusedValue),
);
await interaction.respond(
choices.map((choice) => ({ name: choice, value: choice })),
);
});
To make a response only visible to the user who ran the command:
import { Command } from "@djs-core/runtime";
import { MessageFlags } from "discord.js";
export default new Command()
.setDescription("A private command")
.run(async (interaction) => {
await interaction.reply({
content: "This message is only visible to you!",
flags: [MessageFlags.Ephemeral],
});
});
Commands can be organized into subcommands using the file structure:
src/interactions/commands/
├── ping.ts → /ping
├── admin/
│ ├── kick.ts → /admin kick
│ └── ban.ts → /admin ban
└── shop/
├── buy.ts → /shop buy
└── sell.ts → /shop sell
You can restrict commands to users with specific permissions. This is essential for administrative or sensitive commands.
import { Command } from "@djs-core/runtime";
import { PermissionFlagsBits } from "discord.js";
export default new Command()
.setDescription("Restart the bot")
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
.run(async (interaction) => {
await interaction.reply("Bot restarting...");
// Restart logic here
});