Add pagination to discord bot using buttons or menu.
Version 16.6.0 or newer of Node.js is required
npm install @discordx/pagination
yarn add @discordx/pagination
- Embed pagination with discord's new buttons and select menu
- fully customizable (You can open an issue if you find something missing, so that we can fix it)
- Large list support (for examples 1000 items)
- Support (
embeds: (string | MessageEmbed | MessageOptions)[] | Pagination
) - support interaction/message/channel to send pages
- page resolver for dynamic usage
import {
Pagination,
PaginationResolver,
PaginationType,
} from "@discordx/pagination";
import type {
CommandInteraction,
MessageActionRowComponentBuilder,
MessageOptions,
} from "discord.js";
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
EmbedBuilder,
} from "discord.js";
import type { ArgsOf } from "discordx";
import { Discord, On, Slash } from "discordx";
function GeneratePages(limit?: number): MessageOptions[] {
const pages = Array.from(Array(limit ?? 20).keys()).map((i) => {
return { content: `I am ${i + 1}`, embed: `Demo ${i + 1}` };
});
return pages.map((page) => {
return {
content: page.content,
embeds: [new MessageEmbed().setTitle(page.embed)],
};
});
}
@Discord()
export class Example {
// example: message
@On({ event: "messageCreate" })
messageCreate([message]: ArgsOf<"messageCreate">): void {
if (message.content === "paginated demo") {
new Pagination(message, GeneratePages(), {
type: PaginationType.Button,
}).send();
}
}
// example: any text channel
@On({ event: "messageCreate" })
messageCreateChannel([message]: ArgsOf<"messageCreate">): void {
if (message.content === "paginated channel demo") {
new Pagination(message.channel, GeneratePages(), {
type: PaginationType.Button,
}).send();
}
}
// example: simple slash with button pagination
@Slash({ description: "Simple slash with button pagination", name: "demo-a" })
async demoA(interaction: CommandInteraction): Promise<void> {
const embedX = new PaginationResolver((page, pagination) => {
if (page === 3) {
// example to replace pagination with another pagination data
pagination.currentPage = 0; // reset current page, because this is gonna be first page
pagination.maxLength = 5; // new max length for new pagination
pagination.embeds = ["1", "2", "3", "4", "5"]; // page reference can be resolver as well
return pagination.embeds[pagination.currentPage] ?? "unknown"; // the first page, must select ourselves
}
return `page v2 ${page}`;
}, 25);
const pagination = new Pagination(interaction, embedX, {
onTimeout: () => interaction.deleteReply(),
start: {
emoji: { name: "🙂" },
},
time: 5 * 1000,
type: PaginationType.Button,
});
await pagination.send();
}
// example: simple slash with menu pagination
@Slash({ description: "Simple slash with menu pagination", name: "demo-b" })
demoB(interaction: CommandInteraction): void {
new Pagination(interaction, GeneratePages(), {
time: 5 * 1000,
type: PaginationType.SelectMenu,
}).send();
}
// example: simple string array
@Slash({ description: "Simple string array", name: "demo-c" })
demoC(interaction: CommandInteraction): void {
new Pagination(
interaction,
Array.from(Array(20).keys()).map((i) => i.toString()),
).send();
}
// example: array of custom message options
@Slash({ description: "Array of custom message options", name: "demo-d" })
demoD(interaction: CommandInteraction): void {
new Pagination(interaction, [
{
content: "Page 1",
},
{
content: "Page 2",
embeds: [new EmbedBuilder({ title: "It's me embed 2" })],
},
{
components: [
new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(
[
new ButtonBuilder({
customId: "myCustomId",
label: "My Custom Button",
style: ButtonStyle.Primary,
}),
],
),
],
content: "Page 3",
embeds: [new EmbedBuilder({ title: "It's me embed 3" })],
},
]).send();
}
}
Name | Type | Default | Description |
---|---|---|---|
enableExit | boolean | false | Enable early exit pagination |
ephemeral | boolean | undefined | Enable ephemeral |
initialPage | number | 0 | Initial page |
onTimeout | Function | undefined | Timeout callback |
showStartEnd | boolean | number | true | Show start/end |
time | number | 3e5 | Timeout for pagination in ms |
type | PaginationType | BUTTON | Pagination type |
When pagination options are not defined, SELECT_MENU will be used if there are more than 20 pages.
The following options are only available, if you have set type to BUTTON
Name | Type | Description |
---|---|---|
end | ButtonOptions | End Button options |
exit | ButtonOptions | Exit Button options |
next | ButtonOptions | Next Button options |
previous | ButtonOptions | Previous Button options |
start | ButtonOptions | Start Button options |
Name | Type | Description |
---|---|---|
emoji | EmojiIdentifierResolvable | Button Emoji |
id | string | Button Id |
label | string | Button Label |
style | PRIMARY| SECONDARY |SUCCESS | DANGER | Button Style |
The following options are only available, if you have set type to SELECT_MENU
Name | Type | Default | Description |
---|---|---|---|
labels.end | string | End |
label |
labels.exit | string | Exit Pagination |
label |
labels.start | string | Start |
label |
menuId | string | discordx@pagination@menu |
Menu custom id |
pageText | string | string[] | Page {page} |
Menu page text |
placeholder | string | Select page |
Menu placeholder |
- Check frequently asked questions
- Check examples
- Ask in the community Discord server