Button layout issue in Discord attendance bot - elements appearing in wrong sequence

I’m working on a Discord bot for tracking work attendance and having trouble with the UI layout. The buttons for checking in and out are showing up after the text content instead of before it like I want.

import discord
from discord.ext import commands
from datetime import datetime
import config

active_users = []
activity_log = []
client = discord.Client(intents=discord.Intents.all())

class AttendanceView(discord.ui.View):
    @discord.ui.button(label="Check In", style=discord.ButtonStyle.primary, custom_id="checkin")
    async def checkin_handler(self, interaction: discord.Interaction, button: discord.ui.Button):
        if interaction.user.display_name not in active_users:
            view = AttendanceView()
            active_users.append(interaction.user.display_name)
            activity_log.append(f"{interaction.user.display_name} checked in at {datetime.now().strftime('%H:%M:%S')}")
            
            await interaction.message.edit(content=build_message(), view=view)
        await interaction.response.defer()

    @discord.ui.button(label="Check Out", style=discord.ButtonStyle.secondary, custom_id="checkout")
    async def checkout_handler(self, interaction: discord.Interaction, button: discord.ui.Button):
        if interaction.user.display_name in active_users:
            view = AttendanceView()
            active_users.remove(interaction.user.display_name)
            activity_log.append(f"{interaction.user.display_name} checked out at {datetime.now().strftime('%H:%M:%S')}")
            
            await interaction.message.edit(content=build_message(), view=view)
        await interaction.response.defer()

async def setup_tracker(channel):
    view = AttendanceView()
    message_content = build_message()
    msg = await channel.send(message_content, view=view)
    updated_content = build_message()
    await msg.edit(view=view, content=updated_content)

def build_message():
    current_workers = '\n'.join(active_users) if active_users else 'Nobody currently working'
    recent_activity = '\n'.join(activity_log) if activity_log else 'No activity recorded yet'
    message = f"**Currently Active:**\n{current_workers}\n\n**Activity History:**\n{recent_activity}"
    return message

@client.event
async def on_ready():
    print('Attendance bot is running')
    target_channel = client.get_channel(1105561415038812311)
    await setup_tracker(target_channel)

client.run(config.BOT_TOKEN)

I expected the buttons to appear above the status text but they keep showing below it. Any ideas what might be causing this ordering problem?

Yeah, that’s just how Discord works - UI components always show up after message content no matter how you code it. Discord’s client displays text first, then interactive stuff below. I hit this same issue building a ticket bot. My workaround was using an embed with buttons at the bottom and keeping the description short - just ‘Use the buttons below’ or whatever. Then I’d send the detailed status info in a follow-up message right after. Makes it look like the buttons come first in the flow even though they’re still technically below their text.

Discord hardcodes buttons under content - you can’t change that. I’ve tried different approaches and nothing works. Maybe add emojis or visual dividers to make it feel more natural? Like “:down_arrow: Use buttons below :down_arrow:” at the end of your status message so users know where to look.

Had the same issue with my first Discord bot. Discord automatically renders buttons below text content - that’s just how their message structure works. You can’t put buttons above text through the API.

What you’re seeing is normal behavior. If you need interactive elements first, you could split things into separate messages - one for buttons, another for status info. But that makes the interface feel choppy. Better approach: restructure your text so the important stuff goes at the top, then the button placement won’t matter as much.

This topic was automatically closed 4 days after the last reply. New replies are no longer allowed.