Skip to main content

 

Discord serverNPM versionNPM downloadsBuild statuspaypal

Create a discord bot with TypeScript and Decorators!

📖 Introduction

Add pagination to discord bot using buttons or menu.

💻 Installation

Version 16.6.0 or newer of Node.js is required

npm install @discordx/pagination
yarn add @discordx/pagination

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

discord embed pagination

Example

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();
}
}

Options

NameTypeDefaultDescription
enableExitbooleanfalseEnable early exit pagination
ephemeralbooleanundefinedEnable ephemeral
initialPagenumber0Initial page
onTimeoutFunctionundefinedTimeout callback
showStartEndboolean | numbertrueShow start/end
timenumber3e5Timeout for pagination in ms
typePaginationTypeBUTTONPagination type

When pagination options are not defined, SELECT_MENU will be used if there are more than 20 pages.

Button Options

The following options are only available, if you have set type to BUTTON

NameTypeDescription
endButtonOptionsEnd Button options
exitButtonOptionsExit Button options
nextButtonOptionsNext Button options
previousButtonOptionsPrevious Button options
startButtonOptionsStart Button options

Type: ButtonOptions

NameTypeDescription
emojiEmojiIdentifierResolvableButton Emoji
idstringButton Id
labelstringButton Label
stylePRIMARY| SECONDARY |SUCCESS | DANGERButton Style

SELECT_MENU Options

The following options are only available, if you have set type to SELECT_MENU

NameTypeDefaultDescription
labels.endstringEndlabel
labels.exitstringExit Paginationlabel
labels.startstringStartlabel
menuIdstringdiscordx@pagination@menuMenu custom id
pageTextstring | string[]Page {page}Menu page text
placeholderstringSelect pageMenu placeholder

📜 Documentation

☎️ Need help?

💖 Thank you

You can support discordx by giving it a GitHub star.