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 } from "@discordx/pagination";
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
EmbedBuilder,
Events,
type CommandInteraction,
type MessageActionRowComponentBuilder,
} from "discord.js";
import { Discord, On, Slash, type ArgsOf } 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: Events.MessageCreate })
async messageCreate([message]: ArgsOf<Events.MessageCreate>): Promise<void> {
if (message.content === "paginated demo") {
const pagination = new Pagination(message, GeneratePages());
await pagination.send();
}
}

// example: any text channel
@On({ event: Events.MessageCreate })
async messageCreateChannel([
message,
]: ArgsOf<Events.MessageCreate>): Promise<void> {
if (message.content === "paginated channel demo") {
const pagination = new Pagination(message.channel, GeneratePages());
await pagination.send();
}
}

// Example: simple slash with button pagination
@Slash({ description: "Simple slash with button pagination", name: "demo-a" })
async demoA(interaction: CommandInteraction): Promise<void> {
const resolver = new PaginationResolver((page, paginator) => {
// Let's update our pagination dynamically
if (page === 3) {
// Set pages, this can can be resolver as well
paginator.setPages([
{ content: "1" },
{ content: "2" },
{ content: "3" },
{ content: "4" },
{ content: "5" },
]);

return { content: "Pagination updated" };
}

return { content: `page v2 ${page + 1}` };
}, 25);

const pagination = new Pagination(interaction, resolver, {
onTimeout: async () => {
try {
await interaction.deleteReply();
} catch (err) {
// ignore
}
},
buttons: {
backward: {
emoji: { name: "🙂" },
},
},
time: 60_000,
});

await pagination.send();
}

// example: simple slash with menu pagination
@Slash({ description: "Simple slash with menu pagination", name: "demo-b" })
async demoB(interaction: CommandInteraction): Promise<void> {
const pagination = new Pagination(interaction, GeneratePages(), {
time: 60_000,
});

await pagination.send();
}

// example: simple string array
@Slash({ description: "Simple string array", name: "demo-c" })
async demoC(interaction: CommandInteraction): Promise<void> {
const pagination = new Pagination(
interaction,
Array.from(Array(200).keys()).map((i) => ({
content: (i + 1).toString(),
})),
);

await pagination.send();
}

// example: array of custom message options
@Slash({ description: "Array of custom message options", name: "demo-d" })
async demoD(interaction: CommandInteraction): Promise<void> {
const pagination = 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" })],
},
]);

await pagination.send();
}
}

Options

Basic Options​

NameTypeDefaultDescription
debugbooleanfalseEnable debug logging
ephemeralbooleanundefinedSet ephemeral response
initialPagenumber0Initial page number
itemsPerPagenumberundefinedNumber of items shown per page in select menu
onTimeoutFunctionundefinedCallback function when pagination times out

Button Navigation Options​

The following options are available under the buttons configuration:

NameTypeDescription
previousButtonOptionsPrevious button configuration
backwardButtonOptionsBackward button configuration (-10 pages)
forwardButtonOptionsForward button configuration (+10 pages)
nextButtonOptionsNext button configuration
exitButtonOptionsExit button configuration
skipAmountnumberNumber of pages to skip with skip buttons (default: 10)

ButtonOptions Structure​

NameTypeDescription
enabledBooleanShow button in row
emojiComponentEmojiResolvable | nullButton emoji
idstringCustom button ID
labelstringButton label text
styleButtonStyleButton style (PRIMARY|SECONDARY|SUCCESS|DANGER)

Select Menu Options​

The following options are available under the selectMenu configuration:

NameTypeDefaultDescription
labels.startstring"Start"Start label text
labels.endstring"End"End label text
menuIdstring"discordx@pagination@menu"Custom select menu ID
pageTextstring | string[]"Page {page}"Page text format (use {page} for page number)
rangePlaceholderFormatstringundefinedCustom range placeholder format (use {start}, {end}, {total})

📜 Documentation

☎️ Need help?

💖 Thank you

You can support discordx by giving it a GitHub star.