📜 Commands
Slash Commands are one of the primary ways to use your Discord Bot. They allow users to interact with your bot by typing /
followed by the command name, maybe some options, and hitting enter.
Building Slash Commands is streamlined with Robo.js, which also handles automatic registration.
Creating Slash Commands
Create a file in your project's src/commands
folder named after your Slash Command.
- Javascript
- Typescript
export default (interaction) => {
interaction.reply('Pong!')
}
import type { ChatInputCommandInteraction } from 'discord.js'
import type { CommandResult } from 'robo.js'
export default (interaction: ChatInputCommandInteraction): CommandResult => {
interaction.reply('Pong!')
}
That's it! Your /ping
command is fully set up—give it a try!
Don't see your new command? Try restarting your Discord Client to refresh your cache.
Alternatively, you can also return your reply directly.
- Javascript
- Typescript
export default async () => {
return 'Pong!'
}
import type { CommandResult } from 'robo.js'
export default async (): Promise<CommandResult> => {
return 'Pong!'
}
This kicks in Sage Mode—a hidden power that handles interactions and defers slow async functions!
Subcommands and Subcommand Groups
Wanna go deeper? Make a folder inside src/commands
with the parent command name and its own files.
- Javascript
- Typescript
export default async (interaction) => {
const everyoneRole = interaction.guild.roles.everyone
await interaction.channel.permissionOverwrites.edit(everyoneRole, {
SendMessages: false,
AddReactions: false
})
return 'This channel is now locked!'
}
import type { ChatInputCommandInteraction } from 'discord.js'
import type { CommandResult } from 'robo.js'
export default async (interaction: ChatInputCommandInteraction): Promise<CommandResult> => {
const everyoneRole = interaction.guild.roles.everyone
await interaction.channel.permissionOverwrites.edit(everyoneRole, {
SendMessages: false,
AddReactions: false
})
return 'This channel is now locked!'
}
We can go even deeper with Subcommand Groups. Just add another folder inside the parent command folder.
- Javascript
- Typescript
import { client } from 'robo.js'
export default async (interaction) => {
await client.user.setPresence({
status: 'idle'
})
return "I'm now idle!"
}
import { client } from 'robo.js'
import type { ChatInputCommandInteraction } from 'discord.js'
import type { CommandResult } from 'robo.js'
export default async (interaction: ChatInputCommandInteraction): Promise<CommandResult> => {
await client.user.setPresence({
status: 'idle'
})
return "I'm now idle!"
}
Pretty cool, right? Literally just folders and files!
src
└── commands
├── channel
│ └── lock.js
└── bot
└── status
└── idle.js
Customizing Commands
Give your commands some context with descriptions. You can do this by exporting a config
object from your command file.
import { createCommandConfig } from 'robo.js'
export const config = createCommandConfig({
description: 'Responds with Pong!'
})
For TypeScript users, you can add typings for both the config
object and the command result.
import { createCommandConfig } from 'robo.js'
import type { CommandResult } from 'robo.js'
export const config = createCommandConfig({
description: 'Responds with Pong!'
})
export default (): CommandResult => {
return 'Pong!'
}
The config
object also lets you customize stuff like locale translations, Sage options, and command timeouts. To understand more about the available duration options, check out the configuration section.
Command Options
Robo.js allows you to further customize your commands with options. You can define these options in your config
object and then access their values in your command function.
- Javascript
- Typescript
import { createCommandConfig } from 'robo.js'
export const config = createCommandConfig({
description: 'Responds with Pong!',
options: [
{
name: 'loud',
description: 'Respond loudly?',
type: 'boolean'
}
]
})
export default (interaction) => {
const loud = interaction.options.get('loud')?.value as boolean
return loud ? 'PONG!!!' : 'Pong!'
}
import { createCommandConfig } from 'robo.js'
import type { CommandResult } from 'robo.js'
import type { CommandInteraction } from 'discord.js'
export const config = createCommandConfig({
description: 'Responds with Pong!',
options: [
{
name: 'loud',
description: 'Respond loudly?',
type: 'boolean'
}
]
} as const)
export default (interaction: CommandInteraction): CommandResult => {
const loud = interaction.options.get('loud')?.value as boolean
return loud ? 'PONG!!!' : 'Pong!'
}
You can also use a second parameter next to the interaction object to access the options directly. These are automatically parsed and passed to your command function, with full type support too!
- Javascript
- Typescript
import { createCommandConfig } from 'robo.js'
export const config = createCommandConfig({
description: 'Responds with Pong!',
options: [
{
name: 'loud',
description: 'Respond loudly?',
type: 'boolean'
}
]
})
export default (interaction, options) => {
return options.loud ? 'PONG!!!' : 'Pong!'
}
import { createCommandConfig } from 'robo.js'
import type { CommandOptions, CommandResult } from 'robo.js'
import type { CommandInteraction } from 'discord.js'
export const config = createCommandConfig({
description: 'Responds with Pong!',
options: [
{
name: 'loud',
description: 'Respond loudly?',
type: 'boolean'
}
]
} as const)
export default (interaction: CommandInteraction, options: CommandOptions<typeof config>): CommandResult => {
return options.loud ? 'PONG!!!' : 'Pong!'
}
Heads up!
createCommandConfig
andas const
are important for TypeScript!createCommandConfig
creates a command configuration object with the correct type, which tells your editor which options are available for your command for better autocompletion and type checking.
Want to explore more options? Check the configuration section.
Choices
You can have predefined choices for your options. Just add a choices
array to your option object.
- Javascript
- Typescript
import { createCommandConfig } from 'robo.js'
export const config = createCommandConfig({
description: 'Chooses a color',
options: [
{
name: 'color',
description: 'Your favorite color',
type: 'string',
choices: [
{ name: 'Red', value: 'red' },
{ name: 'Green', value: 'green' },
{ name: 'Blue', value: 'blue' }
]
}
]
})
import { createCommandConfig } from 'robo.js'
export const config = createCommandConfig({
description: 'Chooses a color',
options: [
{
name: 'color',
description: 'Your favorite color',
type: 'string',
choices: [
{ name: 'Red', value: 'red' },
{ name: 'Green', value: 'green' },
{ name: 'Blue', value: 'blue' }
]
}
]
} as const)
Make sure each choice has a name
and value
. The name
is what the user sees, while the value
is what your command receives.
To dynamically generate choices instead of hardcoding them in advance, see Autocomplete.
Direct Messages
Control whether your command is accessible in direct messages with contexts
.
export const config = {
// ... other config
contexts: ['Guild', 'BotDM']
}
Adding 'BotDM'
alongside 'Guild'
allows the command to be used in direct messages. Remove 'Guild'
if you want to restrict the command to direct messages only.
You can customize defaults in your Robo Config.
Default Member Permissions
Use defaultMemberPermissions
to define server-based permissions for your command. This field accepts PermissionFlagsBits
from Discord.js, allowing you to specify which roles or permissions are needed to access the command in a server context.
import { PermissionFlagsBits } from 'discord.js'
export const config = {
// ... other config
defaultMemberPermissions: PermissionFlagsBits.KickMembers // Only users who can kick members can use this command
}
Remember, server admins can adjust these default permissions for their own servers. Also, due to a Discord quirk, default permissions might not apply as expected to subcommands.
User Installs
By default, commands are only available in guilds where your bot is installed. You can change this behavior with integrationTypes
.
export const config = {
// ... other config
integrationTypes: ['GuildInstall', 'UserInstall']
}
This allows your Slash Commands to be used in any server, even if your bot isn't installed there. Remove 'GuildInstall'
if you want to allow commands only for users that have installed your bot.
You can customize defaults in your Robo Config.
Make sure you update your install settings in the Discord Developer Portal to allow user installs.
Autocomplete
Autocomplete can take your commands to the next level by providing suggestions as users type. You can implement autocomplete by exporting an autocomplete
function in your command file.
- Javascript
- Typescript
import { createCommandConfig } from 'robo.js'
export const config = createCommandConfig({
description: 'Chooses a color',
options: [
{
name: 'color',
description: 'Your favorite color',
type: 'string',
autocomplete: true
}
]
})
const colors = ['red', 'green', 'blue', 'yellow', 'black', 'white', 'pink', 'purple', 'brown']
export default (interaction) => {
return `You chose ${interaction.options.get('color')?.value}`
}
export const autocomplete = (interaction) => {
const colorQuery = interaction.options.get('color')?.value
const filtered = colors.filter((color) => color.startsWith(colorQuery))
return filtered.map((colors) => ({ name: colors, value: colors }))
}
import { createCommandConfig } from 'robo.js'
import type { CommandResult } from 'robo.js'
import type { CommandInteraction, AutocompleteInteraction } from 'discord.js'
export const config = createCommandConfig({
description: 'Chooses a color',
options: [
{
name: 'color',
description: 'Your favorite color',
type: 'string',
autocomplete: true
}
]
})
const colors: Array<string> = ['red', 'green', 'blue', 'yellow', 'black', 'white', 'pink', 'purple', 'brown']
export default (interaction: CommandInteraction): CommandResult => {
return `You chose ${interaction.options.get('color')?.value}`
}
export const autocomplete = (interaction: AutocompleteInteraction) => {
const colorQuery = interaction.options.get('color')?.value as string
const filtered = colors.filter((color) => color.startsWith(colorQuery))
return filtered.map((colors) => ({ name: colors, value: colors }))
}
In this example, the autocomplete
function returns an array of colors that start with the user's input, providing a dynamic and responsive user experience.
Note: the type of the Interaction is: AutocompleteInteraction
Command Registration
The cherry on top? You don't need to manually register your commands. Robo.js handles it for you when you run robo dev
or robo build
, automatically! However, if things go sideways for some reason, you can use the --force
flag to force registration.
npx robo build --force
This will also clean up any commands that are no longer in your commands
directory. Pretty neat, right?