Layout messages
An embed hangs a card under your message text. A layout message drops the plain message entirely and builds everything from pieces: text blocks, images, dividers, boxes with a coloured edge, and your buttons. (Discord calls this Components V2.)
import {
ActionRow,
Button,
Container,
H2,
renderMessage,
Section,
Separator,
Subtext,
TextDisplay,
Thumbnail,
} from "@hyperion-js/jsx";
const message = renderMessage(
<Container accent={0x5865f2}>
<Section
accessory={<Thumbnail url="https://example.com/profile.png" />}
>
<TextDisplay>
<H2>Your profile</H2>
You're all caught up.
<Subtext>Check back later for new tasks.</Subtext>
</TextDisplay>
</Section>
<Separator />
<ActionRow>
<Button customId="profile.refresh" style="primary">
Refresh
</Button>
</ActionRow>
</Container>,
{ ephemeral: true },
);Send it with await interaction.reply(message). renderMessage() returns the
components together with the flag Discord needs, so there's nothing to remember.
{ ephemeral: true } makes the reply private. Leave it out and the same result
also works with update() and editReply().
The pieces
Container: a box around other pieces.accentcolours its edge. Containers sit at the top level and don't nest.TextDisplay: a block of text, with the same formatting as embeds.Section: one to three text displays with anaccessorybeside them, either aThumbnailor aButton.MediaGallery: one to ten images or videos, asMediaGallery.Itemchildren.Separator: space between pieces. It draws a divider line unless you passdivider={false}, andspacing="large"adds more room.ActionRow: your buttons and menus, at the top level or inside a container.
Put a piece in the wrong place (a Thumbnail outside a section, say) and
rendering throws a JSXRenderError that points right at it.
Images
Give each gallery item a URL, plus a short description (alt text) for people who can't see the image:
import { MediaGallery, renderMessage } from "@hyperion-js/jsx";
const message = renderMessage(
<MediaGallery>
<MediaGallery.Item
url="https://example.com/preview.png"
description="Preview of the new profile card"
/>
</MediaGallery>,
);Thumbnail and MediaGallery.Item also take spoiler. To show a file you're
uploading yourself, use an attachment://filename URL and pass the file in the
reply's files option. The package doesn't upload it for you.
Updating a layout message
A message that starts as a layout message stays one for good. To change it,
render the new version with renderMessage() and pass it to update() or
editReply(). Leave out ephemeral, since a sent message can't change who sees
it. And don't add content or embeds; put visible text in a TextDisplay
instead.
Keep the whole message to 40 components, counting everything nested inside. Interactive custom IDs must be unique, as they are for any buttons and menus.
Next up: modals. The layout reference lists every prop and placement rule. Using Hyperion? See how buttons in layout messages reach your handlers.