A delightfully cute and professional Discord embed paginator for Discord.js v14+ β¨
Transform your bot's embed displays into beautiful, interactive experiences with customizable buttons, adorable messages, and powerful features that users will love!
- π¨ Fully Customizable - Buttons, messages, styling, and behavior
- πΈ Cute Default Messages - Adorable responses that add personality
- π TypeScript Ready - Full type safety and IntelliSense support
- π§ Easy to Use - Simple API with sensible defaults
- π― Multiple Navigation Modes - From minimal to advanced layouts
- β‘ Performance Optimized - Efficient collectors and memory management
- π Permission Control - Author-only or public interaction modes
- π Loop Navigation - Optional page wrapping for seamless browsing
- π Page Information - Built-in page info and jump functionality
- π¨ Pre-made Themes - Beautiful button configs ready to use
npm install miyuki-pagination
# or
yarn add miyuki-pagination
# or
pnpm add miyuki-pagination
# or
bun add miyuki-paginationimport { EmbedBuilder } from 'discord.js';
import { MiyukiPaginator } from 'miyuki-pagination';
// Create your embeds
const embeds = [
new EmbedBuilder().setTitle('Page 1').setDescription('First page content! (ββΏβ)'),
new EmbedBuilder().setTitle('Page 2').setDescription('Second page content! β¨'),
new EmbedBuilder().setTitle('Page 3').setDescription('Third page content! πΈ'),
];
// Create and start the paginator
const paginator = new MiyukiPaginator({ embeds });
await paginator.start(interaction);That's it! Your users can now navigate through pages with beautiful, responsive buttons! π
import { SlashCommandBuilder } from 'discord.js';
import { MiyukiPaginator } from 'miyuki-pagination';
export default {
data: new SlashCommandBuilder()
.setName('help')
.setDescription('Show help pages'),
async execute(interaction) {
const helpEmbeds = createHelpEmbeds(); // Your embed creation logic
const paginator = new MiyukiPaginator({
embeds: helpEmbeds,
timeout: 60000,
showPageNumbers: true,
authorOnly: true
});
await paginator.start(interaction);
}
};// For prefix commands or message-based triggers
const paginator = new MiyukiPaginator({ embeds: myEmbeds });
await paginator.startMessage(message, { content: 'Here are your results!' });Use pre-made button configurations for different styles:
import { ButtonConfigs, createMiyukiPaginator } from 'miyuki-pagination';
// Minimal navigation (Previous, Stop, Next)
const minimal = createMiyukiPaginator({
embeds: myEmbeds,
buttons: ButtonConfigs.minimal()
});
// Simple navigation (Previous, Next only)
const simple = createMiyukiPaginator({
embeds: myEmbeds,
buttons: ButtonConfigs.simple()
});
// Advanced navigation (all features)
const advanced = createMiyukiPaginator({
embeds: myEmbeds,
buttons: ButtonConfigs.advanced()
});
// Cute theme with flower emojis! πΈ
const cute = createMiyukiPaginator({
embeds: myEmbeds,
buttons: ButtonConfigs.cute()
});Create your own button layouts:
import { PaginatorButtonType, ButtonStyle } from 'miyuki-pagination';
const paginator = new MiyukiPaginator({
embeds: myEmbeds,
buttons: [
{
type: PaginatorButtonType.PREVIOUS,
emoji: 'β¬
οΈ',
label: 'Back',
style: ButtonStyle.Primary,
position: 0
},
{
type: PaginatorButtonType.STOP,
emoji: 'π',
label: 'Stop',
style: ButtonStyle.Danger,
position: 1
},
{
type: PaginatorButtonType.NEXT,
emoji: 'β‘οΈ',
label: 'Forward',
style: ButtonStyle.Primary,
position: 2
}
]
});Personalize all the messages or add internationalization:
const paginator = new MiyukiPaginator({
embeds: myEmbeds,
responseMessages: {
authorOnlyError: "π« Only you can navigate this menu!",
noEmbedsError: "π
Oops! No content to display.",
pageInfoTitle: "π Navigation Info",
pageInfoDescription: "Current pagination details:",
jumpToPageContent: "π― Jump to page {current} of {total}"
}
});Enable seamless navigation with page wrapping:
const paginator = new MiyukiPaginator({
embeds: myEmbeds,
loopPages: true, // Last page -> First page, First page -> Last page
showPageNumbers: true
});Allow anyone to navigate (not just the command author):
const paginator = new MiyukiPaginator({
embeds: myEmbeds,
authorOnly: false, // Anyone can interact with buttons
timeout: 120000 // Longer timeout for public use
});Add utility buttons for better navigation:
const paginator = new MiyukiPaginator({
embeds: myEmbeds,
allowJumping: true, // Adds jump-to-page button
showPageInfo: true, // Adds page info button
showPageNumbers: true // Shows "Page X of Y" in footer
});Update messages after creating the paginator:
const paginator = new MiyukiPaginator({ embeds: myEmbeds });
// Update a single message
paginator.updateResponseMessage('authorOnlyError', 'Custom error message!');
// Update multiple messages
paginator.updateMultipleMessages({
pageInfoTitle: 'Custom Info Title',
pageInfoDescription: 'Custom description here!'
});Convert data objects to embeds effortlessly:
import { createEmbedsFromContent } from 'miyuki-pagination';
const content = [
{
title: 'Server Rules',
description: 'Please follow these guidelines:',
color: 0xff69b4,
fields: [
{ name: '1. Be Respectful', value: 'Treat everyone kindly', inline: false },
{ name: '2. No Spam', value: 'Keep chat clean', inline: false }
],
thumbnail: 'https://example.com/rules-icon.png'
},
{
title: 'Moderation',
description: 'Information about our moderation system:',
color: 0x00ff00,
fields: [
{ name: 'Warning System', value: '3 strikes policy', inline: true },
{ name: 'Appeal Process', value: 'DM moderators', inline: true }
]
}
];
const embeds = createEmbedsFromContent(content);
const paginator = new MiyukiPaginator({ embeds });Use the factory function for cleaner code:
import { createMiyukiPaginator } from 'miyuki-pagination';
const paginator = createMiyukiPaginator({
embeds: myEmbeds,
timeout: 30000,
authorOnly: false,
loopPages: true
});| Option | Type | Default | Description |
|---|---|---|---|
embeds |
EmbedBuilder[] |
Required | Array of embeds to paginate |
timeout |
number |
60000 |
Timeout in milliseconds |
buttons |
CustomButton[] |
undefined |
Custom button configuration |
useDefaultButtons |
boolean |
true |
Whether to use default buttons |
buttonLabels |
object |
{} |
Custom labels for default buttons |
buttonEmojis |
object |
{} |
Custom emojis for default buttons |
responseMessages |
ResponseMessages |
{} |
Custom response messages |
showPageNumbers |
boolean |
true |
Show "Page X of Y" in footer |
authorOnly |
boolean |
true |
Only author can interact |
maxButtonsPerRow |
number |
5 |
Max buttons per row |
allowJumping |
boolean |
false |
Enable jump-to-page feature |
showPageInfo |
boolean |
false |
Show page info button |
loopPages |
boolean |
false |
Enable page looping |
enum PaginatorButtonType {
FIRST = "first", // Navigate to first page
PREVIOUS = "previous", // Navigate to previous page
NEXT = "next", // Navigate to next page
LAST = "last", // Navigate to last page
STOP = "stop", // Close paginator
JUMP = "jump", // Jump to specific page
INFO = "info" // Show page information
}start(interaction: CommandInteraction)- Start from slash commandstartMessage(message: Message, options?)- Start from regular messageupdateResponseMessage(key, value)- Update single messageupdateMultipleMessages(messages)- Update multiple messagesgetResponseMessage(key)- Get current messagegetAllResponseMessages()- Get all current messages
const helpCategories = [
{
title: 'π General Commands',
description: 'Basic bot functionality',
fields: [
{ name: '/help', value: 'Show this help menu', inline: false },
{ name: '/ping', value: 'Check bot latency', inline: false }
],
color: 0x3498db
},
{
title: 'π΅ Music Commands',
description: 'Music playback features',
fields: [
{ name: '/play', value: 'Play a song', inline: false },
{ name: '/pause', value: 'Pause current song', inline: false }
],
color: 0xe91e63
}
];
const embeds = createEmbedsFromContent(helpCategories);
const paginator = new MiyukiPaginator({
embeds,
buttons: ButtonConfigs.cute(),
timeout: 120000
});
await paginator.start(interaction);async function createMemberPages(guild) {
const members = await guild.members.fetch();
const pages = [];
const membersPerPage = 10;
for (let i = 0; i < members.size; i += membersPerPage) {
const pageMembers = Array.from(members.values()).slice(i, i + membersPerPage);
const embed = new EmbedBuilder()
.setTitle(`π₯ Server Members`)
.setDescription(`Showing ${pageMembers.length} members`)
.setColor(0x00ff00);
pageMembers.forEach(member => {
embed.addFields({
name: member.displayName,
value: `<@${member.id}>`,
inline: true
});
});
pages.push(embed);
}
return pages;
}
// Usage
const memberEmbeds = await createMemberPages(interaction.guild);
const paginator = new MiyukiPaginator({
embeds: memberEmbeds,
authorOnly: false,
showPageInfo: true,
allowJumping: true
});
await paginator.start(interaction);We love contributions! Whether it's bug reports, feature requests, or code improvements:
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Made with β€οΈ and lots of kawaii energy! Special thanks to the Discord.js team for the amazing library.
Miyuki Pagination - Making Discord bot pagination cute and powerful since 2025! β¨
If you love this library, consider giving it a β on GitHub!