Overview
Buttons are interactive components that users can click to trigger actions. CommandKit’s Button component supports all Discord button styles, emojis, and automatic interaction handling.
Basic Usage
import { ActionRow, Button } from 'commandkit';
import { ButtonStyle } from 'discord.js';
const buttons = (
<ActionRow>
<Button style={ButtonStyle.Primary}>Primary</Button>
<Button style={ButtonStyle.Secondary}>Secondary</Button>
<Button style={ButtonStyle.Success}>Success</Button>
<Button style={ButtonStyle.Danger}>Danger</Button>
</ActionRow>
);
await interaction.reply({
content: 'Choose an option:',
components: [buttons],
});
Discord provides 5 button styles:
Primary
Secondary
Success
Danger
Link
<Button style={ButtonStyle.Primary}>Primary Button</Button>
Blurple color - used for main actions<Button style={ButtonStyle.Secondary}>Secondary Button</Button>
Gray color - used for alternative actions<Button style={ButtonStyle.Success}>Success Button</Button>
Green color - used for positive actions<Button style={ButtonStyle.Danger}>Danger Button</Button>
Red color - used for destructive actions<Button style={ButtonStyle.Link} url="https://commandkit.dev">
Visit Website
</Button>
Gray color with link - opens a URL (no interaction handler)
Props
style
ButtonStyle
default:"ButtonStyle.Primary"
The visual style of the button
Custom identifier for the button. Auto-generated if onClick is provided.
The text displayed on the button. Can also be set via children.
children
string | number | boolean
Alternative way to set the button label
Emoji to display on the button (Unicode or custom emoji)
Whether the button is disabled and cannot be clicked
URL for link-style buttons (requires style={ButtonStyle.Link})
Handler called when the button is clicked
onError
EventInterceptorErrorHandler
Handler called when an error occurs in the interaction collector
Handler called when the interaction collector ends
options
CommandKitButtonBuilderInteractionCollectorDispatchContextData
Configuration for the interaction collector (timeout, filters, etc.)
Click Handlers
Basic Handler
import { OnButtonKitClick } from 'commandkit';
import { MessageFlags } from 'discord.js';
const handleClick: OnButtonKitClick = async (interaction, context) => {
await interaction.reply({
content: 'Button clicked!',
flags: MessageFlags.Ephemeral,
});
// Dispose of the interaction collector
context.dispose();
};
<Button onClick={handleClick}>Click Me</Button>
Handler with Context
The second parameter provides access to the ButtonKit instance:
const handleClick: OnButtonKitClick = async (interaction, context) => {
// Update the button
context.setDisabled(true);
context.setLabel('Clicked!');
await interaction.update({
components: [/* updated components */],
});
// Clean up after 5 seconds
setTimeout(() => context.dispose(), 5000);
};
Real-World Examples
Confirmation Dialog
import {
Button,
ActionRow,
CommandData,
OnButtonKitClick,
ChatInputCommand,
} from 'commandkit';
import { ButtonStyle, MessageFlags } from 'discord.js';
export const command: CommandData = {
name: 'delete',
description: 'Delete an item with confirmation',
};
const handleConfirm: OnButtonKitClick = async (interaction, context) => {
await interaction.reply({
content: 'The item was deleted successfully.',
flags: MessageFlags.Ephemeral,
});
context.dispose();
};
const handleCancel: OnButtonKitClick = async (interaction, context) => {
await interaction.reply({
content: 'The item was not deleted.',
flags: MessageFlags.Ephemeral,
});
context.dispose();
};
export const chatInput: ChatInputCommand = async ({ interaction }) => {
const buttons = (
<ActionRow>
<Button onClick={handleCancel} style={ButtonStyle.Primary}>
Cancel
</Button>
<Button onClick={handleConfirm} style={ButtonStyle.Danger}>
Confirm
</Button>
</ActionRow>
);
await interaction.reply({
content: 'Are you sure you want to delete this item?',
components: [buttons],
});
};
const handleButtonClick: OnButtonKitClick = async (interaction) => {
const { customId } = interaction;
await interaction.reply({
content: `You clicked button "${customId}"!`,
flags: MessageFlags.Ephemeral,
});
};
function ButtonGrid() {
return (
<>
{Array.from({ length: 5 }, (_, i) => (
<ActionRow key={i}>
{Array.from({ length: 5 }, (_, j) => (
<Button
key={j}
onClick={handleButtonClick}
customId={`button-${i}-${j}`}
>
{i * 5 + j + 1}
</Button>
))}
</ActionRow>
))}
</>
);
}
<ActionRow>
<Button style={ButtonStyle.Link} url="https://commandkit.dev">
Documentation
</Button>
<Button style={ButtonStyle.Link} url="https://discord.gg/commandkit">
Support Server
</Button>
</ActionRow>
Unicode Emoji
<Button emoji="⚡" style={ButtonStyle.Primary}>
Electric
</Button>
Custom Emoji
<Button
emoji={{ id: '123456789', name: 'customEmoji' }}
style={ButtonStyle.Primary}
>
Custom
</Button>
Emoji Only
<Button emoji="🔥" style={ButtonStyle.Primary} />
<ActionRow>
<Button disabled>Cannot Click</Button>
<Button>Can Click</Button>
</ActionRow>
Interaction Collector Options
Customize how long buttons remain active and how they behave:
const options = {
// How long the collector stays active (default: 5 minutes)
time: 10 * 60 * 1000, // 10 minutes
// Reset timer on each interaction (default: true)
autoReset: true,
// Only allow one interaction (default: false)
once: false,
// Filter which interactions are handled
filter: (interaction) => interaction.user.id === userId,
// Called when collector ends
onEnd: (reason) => console.log(`Ended: ${reason}`),
};
<Button onClick={handleClick} options={options}>
Click Me
</Button>
Best Practices
Always dispose collectors - Call context.dispose() in your click handlers to clean up interaction collectors and prevent memory leaks.
Use appropriate styles - Choose button styles that match the action’s intent (e.g., Danger for destructive actions).
Limit buttons per row - Discord allows a maximum of 5 buttons per ActionRow.
Handle errors gracefully - Use the onError prop to handle interaction collector errors.
- Maximum 5 buttons per ActionRow
- Maximum 5 ActionRows per message (25 buttons total)
- Link buttons cannot have click handlers
- Button labels are limited to 80 characters
- Custom IDs are limited to 100 characters
See Also