logo

Constatic

Discord Bot BaseCommandsAutocomplete

Autocomplete

How to create discord autocomplete commands

Creating autocomplete options

Imagine that you want to provide choices for a command option but in a dynamic way, for example a command to search for videos on YouTube. You can use the autocomplete option, so that based on what the user types in that option, you can search APIs and return a list of choices.

It's required have a slash command to create an autocomplete option

You can create an autocomplete option in your command and respond to it using the autocomplete method above run

command.ts
createCommand({
	name: "search",
	description: "Search command",
	type: ApplicationCommandType.ChatInput,
	options: [
		{
			name: "query",
			description: "Query",
			type: ApplicationCommandOptionType.String,
			autocomplete: true,
			required,
		}
	],
	async autocomplete(interaction) { 
		const focused = interaction.options.getFocused(); 
		const results = await searchData(focused); 
		if (results.length < 1) return; 
		const choices = results.map(data => ({ 
			name: data.title, value: data.url
		})); 
		return choices; 
	},
	async run(interaction){
		const { options } = interaction;
 
		const query = options.getString("termo", true);
		
		interaction.reply({ flags: ["Ephemeral"], content: query });
	}
});

Note that you can only return options, as the autocomplete command handler will automatically limit the array items to 25

// ...
	return choices; 
// ...

Here's what the internal function of the autocomplete command handler looks like:

// ...
const command = baseStorage.commands.get(interaction.commandName);
if (command && "autocomplete" in command && command.autocomplete){
    const choices = await command.autocomplete(interaction);
    if (choices && Array.isArray(choices)){
        interaction.respond(choices.slice(0, 25));
    }
};
// ...

If you have a large number of items, use autocomplete to try to find it

command.ts
createCommand({
    // ...
    async autocomplete(interaction) {
		const { options, guild } = interaction;
 
        const focused = options.getFocused();
        const documents = await db.get(guild.id);
 
        const filtered = documents.filter(
            data => data.address.toLowercase().includes(focused.toLowercase())
        )
        if (filtered.length < 1) return;
        return filtered.map(data => ({
			name: data.title, value: data.url
		}));
	},
    // ...
})

If you prefer, you can use the interaction's respond method as you normally would:

	return choices; 
	interaction.respond(choices.slice(0, 25)) 

On this page