Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/disgoorg/disgo/llms.txt

Use this file to discover all available pages before exploring further.

Message components allow you to create interactive elements like buttons and select menus that users can click on directly in Discord messages.

Buttons

Buttons are clickable components that can trigger actions in your bot.

Creating buttons

discord.NewPrimaryButton("Click me!", "button_id")

Adding buttons to messages

Buttons must be placed inside an action row:
_, err := client.Rest.CreateMessage(channelID, discord.MessageCreate{
    Content: "Choose an option:",
    Components: []discord.LayoutComponent{
        discord.NewActionRow(
            discord.NewPrimaryButton("Option 1", "option_1"),
            discord.NewPrimaryButton("Option 2", "option_2"),
            discord.NewDangerButton("Cancel", "cancel"),
        ),
    },
})
Each action row can contain up to 5 buttons. You can have up to 5 action rows per message.

Handling button clicks

Listen for button interaction events:
bot.WithEventListenerFunc(func(event *events.ComponentInteractionCreate) {
    if event.ButtonInteractionData().CustomID() == "option_1" {
        _ = event.CreateMessage(discord.MessageCreate{
            Content: "You selected Option 1!",
            Flags:   discord.MessageFlagEphemeral,
        })
    }
})

Complete button example

package main

import (
    "context"
    "log/slog"
    "os"
    "os/signal"
    "syscall"

    "github.com/disgoorg/disgo"
    "github.com/disgoorg/disgo/bot"
    "github.com/disgoorg/disgo/discord"
    "github.com/disgoorg/disgo/events"
    "github.com/disgoorg/disgo/gateway"
)

var token = os.Getenv("disgo_token")

func main() {
    client, err := disgo.New(token,
        bot.WithGatewayConfigOpts(
            gateway.WithIntents(
                gateway.IntentGuilds,
                gateway.IntentGuildMessages,
            ),
        ),
        bot.WithEventListenerFunc(func(event *events.MessageCreate) {
            if event.Message.Author.Bot {
                return
            }
            if event.Message.Content == "buttons" {
                _, _ = event.Client().Rest.CreateMessage(
                    event.ChannelID,
                    discord.MessageCreate{
                        Content: "Choose an action:",
                        Components: []discord.LayoutComponent{
                            discord.NewActionRow(
                                discord.NewSuccessButton("Approve", "approve"),
                                discord.NewDangerButton("Reject", "reject"),
                            ),
                        },
                    },
                )
            }
        }),
        bot.WithEventListenerFunc(func(event *events.ComponentInteractionCreate) {
            customID := event.ButtonInteractionData().CustomID()
            var response string
            if customID == "approve" {
                response = "✅ Approved!"
            } else if customID == "reject" {
                response = "❌ Rejected!"
            }
            _ = event.CreateMessage(discord.MessageCreate{
                Content: response,
                Flags:   discord.MessageFlagEphemeral,
            })
        }),
    )
    if err != nil {
        slog.Error("error while building bot", slog.Any("err", err))
        return
    }
    defer client.Close(context.TODO())

    if err = client.OpenGateway(context.TODO()); err != nil {
        slog.Error("error while connecting to gateway", slog.Any("err", err))
        return
    }

    slog.Info("bot is running. Press CTRL-C to exit.")
    s := make(chan os.Signal, 1)
    signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
    <-s
}

Select menus

Select menus allow users to choose from a dropdown list of options.

String select menu

The most common type of select menu with custom string values:
discord.NewStringSelectMenu(
    "color_select",
    "Choose a color",
    discord.NewStringSelectMenuOption("Red", "red"),
    discord.NewStringSelectMenuOption("Blue", "blue"),
    discord.NewStringSelectMenuOption("Green", "green"),
)

User select menu

Allows selecting Discord users:
discord.NewUserSelectMenu("user_select", "Select a user")

Role select menu

Allows selecting Discord roles:
discord.NewRoleSelectMenu("role_select", "Select a role")

Channel select menu

Allows selecting Discord channels:
discord.NewChannelSelectMenu("channel_select", "Select a channel")

Mentionable select menu

Allows selecting users or roles:
discord.NewMentionableSelectMenu("mention_select", "Select a user or role")

Setting min and max values

Control how many options users can select:
discord.NewStringSelectMenu(
    "multi_select",
    "Choose your favorite colors",
    discord.NewStringSelectMenuOption("Red", "red"),
    discord.NewStringSelectMenuOption("Blue", "blue"),
    discord.NewStringSelectMenuOption("Green", "green"),
    discord.NewStringSelectMenuOption("Yellow", "yellow"),
).WithMinValues(1).WithMaxValues(3)

Handling select menu interactions

bot.WithEventListenerFunc(func(event *events.ComponentInteractionCreate) {
    data := event.StringSelectMenuInteractionData()
    if data.CustomID() == "color_select" {
        selected := data.Values[0]
        _ = event.CreateMessage(discord.MessageCreate{
            Content: "You selected: " + selected,
            Flags:   discord.MessageFlagEphemeral,
        })
    }
})

Updating components

You can update the message with new components after an interaction:
_ = event.UpdateMessage(discord.MessageUpdate{
    Content: discord.NewNullablePtr("Updated!"),
    Components: &[]discord.LayoutComponent{
        discord.NewActionRow(
            discord.NewSecondaryButton("Done", "done").WithDisabled(true),
        ),
    },
})

Disabling components

Disable components to prevent further interactions:
discord.NewPrimaryButton("Already Clicked", "button_id").WithDisabled(true)

Adding emojis to components

Make your components more visually appealing with emojis:
discord.NewPrimaryButton("Like", "like_button").WithEmoji(
    discord.ComponentEmoji{Name: "👍"},
)

// Or with custom emoji
discord.NewPrimaryButton("Custom", "custom_button").WithEmoji(
    discord.ComponentEmoji{ID: snowflake.ID(123456789)},
)

Components v2

DisGo supports Discord’s new Components v2 system with enhanced layouts:
discord.MessageCreate{
    Flags: discord.MessageFlagIsComponentsV2,
    Components: []discord.LayoutComponent{
        discord.NewContainer(
            discord.NewSection(
                discord.NewTextDisplay("**Song Info**"),
                discord.NewTextDisplay("Artist: Example"),
            ),
            discord.NewActionRow(
                discord.NewPrimaryButton("", "play").WithEmoji(
                    discord.ComponentEmoji{Name: "▶️"},
                ),
                discord.NewPrimaryButton("", "pause").WithEmoji(
                    discord.ComponentEmoji{Name: "⏸️"},
                ),
            ),
        ),
    },
}
Components v2 is a newer Discord feature. Make sure to set the MessageFlagIsComponentsV2 flag when using v2 components.

Using the handler package

The handler package provides cleaner component routing:
import "github.com/disgoorg/disgo/handler"

r := handler.New()
r.Component("/approve/{id}", handleApprove)
r.Component("/reject/{id}", handleReject)

func handleApprove(event *handler.ComponentEvent) error {
    id := event.Vars["id"]
    return event.CreateMessage(discord.MessageCreate{
        Content: "Approved item: " + id,
        Flags:   discord.MessageFlagEphemeral,
    })
}

Best practices

  • Use custom IDs wisely: Make them descriptive and consider including data in the ID (e.g., delete_message_123456)
  • Always respond to interactions: Discord requires a response within 3 seconds
  • Use ephemeral messages: For confirmations or error messages that don’t need to be public
  • Disable components after use: Prevent duplicate actions by disabling buttons after they’re clicked
  • Handle timeouts: Components become invalid after 15 minutes - handle expired interactions gracefully
  • Limit action rows: Don’t overwhelm users with too many buttons

Next steps

Build docs developers (and LLMs) love