or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

assertions.mdcomponents-v2.mdcontext-menu-commands.mdembeds.mdindex.mdmessage-components.mdmodals.mdselect-menus.mdslash-commands.mdutilities.md
tile.json

message-components.mddocs/

Message Components

Message components are interactive elements that can be added to Discord messages, including buttons, text inputs, and action rows for organizing components.

ActionRowBuilder

Container for organizing message components in rows. Generic type parameter specifies which component types it can contain.

class ActionRowBuilder<T extends AnyComponentBuilder> {
  readonly components: T[];

  constructor(data?: Partial<APIActionRowComponent<APIComponentInActionRow>>);
  
  addComponents(...components: RestOrArray<T>): this;
  setComponents(...components: RestOrArray<T>): this;
  spliceComponents(index: number, deleteCount: number, ...components: RestOrArray<T>): this;
  
  toJSON(): APIActionRowComponent<APIComponentInMessageActionRow | APIComponentInModalActionRow>;
}

ButtonBuilder

Interactive button component with various styles and actions.

class ButtonBuilder {
  readonly data: Partial<APIButtonComponent>;

  constructor(data?: APIButtonComponent);
  
  setStyle(style: ButtonStyle): this;
  setURL(url: string): this;
  setCustomId(customId: string): this;
  setEmoji(emoji: APIMessageComponentEmoji): this;
  setDisabled(disabled?: boolean): this;
  setLabel(label: string): this;
  setSKUId(skuId: Snowflake): this;
  
  toJSON(): APIButtonComponent;
}

TextInputBuilder

Text input component for use in modals.

class TextInputBuilder {
  readonly data: Partial<APITextInputComponent>;

  constructor(data?: APITextInputComponent);
  
  setCustomId(customId: string): this;
  setLabel(label: string): this;
  setStyle(style: TextInputStyle): this;
  setMinLength(minLength: number): this;
  setMaxLength(maxLength: number): this;
  setPlaceholder(placeholder: string): this;
  setValue(value: string): this;
  setRequired(required?: boolean): this;
  
  toJSON(): APITextInputComponent;
}

ComponentBuilder

Abstract base class for all component builders.

abstract class ComponentBuilder<ComponentDataType> {
  readonly data: Partial<ComponentDataType>;
  
  constructor(data?: Partial<ComponentDataType>);
  toJSON(): ComponentDataType;
}

Component Types

Button Styles

enum ButtonStyle {
  Primary = 1,
  Secondary = 2,
  Success = 3,
  Danger = 4,
  Link = 5,
  Premium = 6
}

Text Input Styles

enum TextInputStyle {
  Short = 1,
  Paragraph = 2
}

Component Type Unions

type MessageActionRowComponentBuilder =
  | ButtonBuilder
  | ChannelSelectMenuBuilder
  | MentionableSelectMenuBuilder
  | RoleSelectMenuBuilder  
  | StringSelectMenuBuilder
  | UserSelectMenuBuilder;

type ModalActionRowComponentBuilder = TextInputBuilder;

type AnyComponentBuilder = MessageActionRowComponentBuilder | ModalActionRowComponentBuilder;

type MessageComponentBuilder =
  | ActionRowBuilder<MessageActionRowComponentBuilder>
  | MessageActionRowComponentBuilder;

type ModalComponentBuilder = 
  | ActionRowBuilder<ModalActionRowComponentBuilder>
  | ModalActionRowComponentBuilder;

Emoji Structure

interface APIMessageComponentEmoji {
  id?: Snowflake | null;
  name?: string | null;
  animated?: boolean;
}

Usage Examples

Button Examples

import { ButtonBuilder, ActionRowBuilder, ButtonStyle } from "@discordjs/builders";

// Primary button with custom ID
const primaryButton = new ButtonBuilder()
  .setCustomId('primary_button')
  .setLabel('Click Me!')
  .setStyle(ButtonStyle.Primary);

// Link button
const linkButton = new ButtonBuilder()
  .setURL('https://discord.js.org')
  .setLabel('Visit Website')
  .setStyle(ButtonStyle.Link);

// Button with emoji
const emojiButton = new ButtonBuilder()
  .setCustomId('emoji_button')
  .setLabel('React!')
  .setStyle(ButtonStyle.Secondary)
  .setEmoji({
    name: '๐Ÿ‘',
    id: null,
    animated: false
  });

// Disabled button
const disabledButton = new ButtonBuilder()
  .setCustomId('disabled_button')
  .setLabel('Disabled')
  .setStyle(ButtonStyle.Danger)
  .setDisabled(true);

Action Row with Buttons

const row = new ActionRowBuilder<ButtonBuilder>()
  .addComponents(
    new ButtonBuilder()
      .setCustomId('accept')
      .setLabel('Accept')
      .setStyle(ButtonStyle.Success),
    new ButtonBuilder()
      .setCustomId('decline')
      .setLabel('Decline')
      .setStyle(ButtonStyle.Danger),
    new ButtonBuilder()
      .setURL('https://discord.js.org/guide')
      .setLabel('Learn More')
      .setStyle(ButtonStyle.Link)
  );

Text Input Examples

import { TextInputBuilder, TextInputStyle } from "@discordjs/builders";

// Short text input
const nameInput = new TextInputBuilder()
  .setCustomId('user_name')
  .setLabel('What is your name?')
  .setStyle(TextInputStyle.Short)
  .setMinLength(2)
  .setMaxLength(50)
  .setPlaceholder('Enter your name here')
  .setRequired(true);

// Paragraph text input
const feedbackInput = new TextInputBuilder()
  .setCustomId('feedback')
  .setLabel('Tell us about your experience')
  .setStyle(TextInputStyle.Paragraph)
  .setMinLength(10)
  .setMaxLength(1000)
  .setPlaceholder('Share your thoughts...')
  .setValue('Default feedback text')
  .setRequired(false);

Action Row with Text Input

const textInputRow = new ActionRowBuilder<TextInputBuilder>()
  .addComponents(
    new TextInputBuilder()
      .setCustomId('reason')
      .setLabel('Reason for report')
      .setStyle(TextInputStyle.Paragraph)
      .setRequired(true)
  );

Component Manipulation

const row = new ActionRowBuilder<ButtonBuilder>();

// Add components individually
row.addComponents(
  new ButtonBuilder()
    .setCustomId('button1')
    .setLabel('Button 1')
    .setStyle(ButtonStyle.Primary)
);

// Add multiple components
row.addComponents(
  new ButtonBuilder()
    .setCustomId('button2')
    .setLabel('Button 2')
    .setStyle(ButtonStyle.Secondary),
  new ButtonBuilder()
    .setCustomId('button3')
    .setLabel('Button 3')
    .setStyle(ButtonStyle.Success)
);

// Replace component at index 1
row.spliceComponents(1, 1, 
  new ButtonBuilder()
    .setCustomId('new_button')
    .setLabel('Replaced Button')
    .setStyle(ButtonStyle.Danger)
);

// Set all components at once
row.setComponents(
  new ButtonBuilder()
    .setCustomId('only_button')
    .setLabel('Only Button')
    .setStyle(ButtonStyle.Primary)
);

Utility Functions

createComponentBuilder

Creates appropriate component builder from API data.

function createComponentBuilder(data: APIMessageComponent | APIModalComponent): AnyComponentBuilder;

Usage:

import { createComponentBuilder } from "@discordjs/builders";

const apiButtonData = {
  type: 2, // Button
  style: 1, // Primary
  label: 'Click me!',
  custom_id: 'my_button'
};

const button = createComponentBuilder(apiButtonData);

Component Limits

Discord enforces these limits on message components:

  • Action Rows: Maximum 5 action rows per message
  • Buttons: Maximum 5 buttons per action row
  • Select Menus: Maximum 1 select menu per action row
  • Text Inputs: Maximum 5 text inputs per modal
  • Button Label: Maximum 80 characters
  • Text Input Label: Maximum 45 characters
  • Text Input Placeholder: Maximum 100 characters
  • Custom ID: Maximum 100 characters