Skip to main content

Embed, Form, Button

Hướng dẫn sử dụng EmbedBuilder để tạo rich message, form input và các hiệu ứng đặc biệt (slots/animation).


1. Quick Start​

import {
Command,
AutoContext,
SmartMessage,
EmbedBuilder,
} from '@n0xgg04/nezon';
import type { Nezon } from '@n0xgg04/nezon';

@Command('embed')
async function onEmbed(@AutoContext() [managedMessage]: Nezon.AutoContext) {
await managedMessage.reply(
SmartMessage.text('').addEmbed(
new EmbedBuilder()
.setColor('#7c3aed')
.setTitle('Example Embed')
.setDescription('This embed is rendered via EmbedBuilder')
.setFooter('Powered by Nezon'),
),
);
}

2. Cấu trúc EmbedBuilder​

Thành phầnPhương thứcGhi chú
Màu sắc.setColor('#abcdef')Hex hoặc tên màu hợp lệ
Tiêu đề / URL.setTitle() / .setURL()URL click được gắn vào title
Author.setAuthor(name, { icon_url, url })Hữu ích khi show avatar hoặc link ngoài
Nội dung.setDescription() hoặc .setDescriptionMarkdown()Markdown tự động wrap
Thumbnail / Image.setThumbnail(url) / .setImage(url)Hỗ trợ preview nhỏ và ảnh lớn
Footer.setFooter(text, iconUrl?)Thường dùng để hiển thị nguồn/cập nhật
Timestamp.setTimestamp()Không truyền param => mặc định thời điểm hiện tại

3. Fields & Media​

addField(name, value, inline?)​

new EmbedBuilder()
.setTitle("User Info")
.addField("Username", "john_doe", true)
.addField("Level", "42", true)
.addField("Status", "Online", true)
.addField("Description", "Long text...", false);
  • inline: true → hiển thị cùng hàng (tối đa 3 field/line).
  • inline: false → field chiếm toàn dòng.

Ảnh minh hoạ​

new EmbedBuilder()
.setColor("#0ea5e9")
.setTitle("Rich Embed")
.setThumbnail("https://example.com/thumb.jpg")
.addField("Field 1", "Value 1", true)
.addField("Field 2", "Value 2", true)
.setImage("https://example.com/hero.jpg")
.setFooter("Footer text", "https://example.com/footer-icon.png");

4. Form Inputs​

Embed hỗ trợ inline forms thông qua addTextField và addSelectField.

new EmbedBuilder()
.setTitle("POLL CREATOR")
.addTextField("Title", "title", {
placeholder: "Nhập tiêu đề",
defaultValue: "",
})
.addTextField("Expired Time (hour)", "expired", {
placeholder: "168",
defaultValue: 168,
isNumber: true,
})
.addSelectField(
"Type",
"type",
[
{ label: "Single choice", value: "SINGLE" },
{ label: "Multiple choice", value: "MULTIPLE" },
],
"SINGLE"
);

Inputs được client render sẵn, giá trị submit được gửi về component handler/onclick handler tương ứng.


5. Kết hợp Buttons​

import { ButtonBuilder, ButtonStyle } from "@n0xgg04/nezon";

SmartMessage.text("")
.addEmbed(
new EmbedBuilder()
.setColor("#0ea5e9")
.setTitle("Action Required")
.setDescription("Please choose an option")
)
.addButton(
new ButtonBuilder().setLabel("Approve").setStyle(ButtonStyle.Success)
)
.addButton(
new ButtonBuilder().setLabel("Reject").setStyle(ButtonStyle.Danger)
);

Buttons vẫn là component riêng nhưng thường đi kèm embed để tạo UI hoàn chỉnh.


6. Animated Image / Slots​

Để tái hiện hiệu ứng như utility bot (quay → dừng), gửi 2 embed:

import type { Nezon, NezonUtilsService } from '@n0xgg04/nezon';
import { NezonUtils } from '@n0xgg04/nezon';

@Command('slots')
async function onSlots(
@AutoContext() [managedMessage]: Nezon.AutoContext,
@NezonUtils() utils: NezonUtilsService,
) {
const pool = [
['1.png', '2.png', '3.png'],
['4.png', '5.png', '6.png'],
['7.png', '8.png', '9.png'],
];

// 1) gửi animation quay
const ack = await managedMessage.reply(
SmartMessage.text('').addEmbed(
new EmbedBuilder()
.setColor('#1F8B4C')
.setTitle('🎰 Kết quả Slots 🎰')
.addAnimatedImage({
id: 'slots',
imageUrl: 'https://cdn.mezon.ai/.../slots.png',
positionUrl: 'https://cdn.mezon.ai/.../slots.json',
pool,
repeat: 3,
duration: 0.35,
}),
),
);

if (!ack?.message_id || !ack?.channel_id) return;

// 2) cập nhật embed kết quả sau 1.3s
setTimeout(async () => {
const animatedMessage = await utils.getManagedMessage(
ack.message_id,
ack.channel_id,
);
if (!animatedMessage) return;

await animatedMessage.update(
SmartMessage.text('').addEmbed(
new EmbedBuilder()
.setColor('#1F8B4C')
.setTitle('🎰 Kết quả Slots 🎰')
.addAnimatedImage({
id: 'slots-result',
imageUrl: 'https://cdn.mezon.ai/.../slots.png',
positionUrl: 'https://cdn.mezon.ai/.../slots.json',
pool,
repeat: 3,
duration: 0.35,
isResult: true,
extra: {
jackpot: 1337517,
},
}),
),
);
}, 1300);
}

Lưu ý quan trọng

  • pool phải khớp với asset animation của bạn.
  • repeat/duration điều chỉnh tốc độ quay (thường 0.3–0.4s).
  • Dùng isResult = true để báo client “đã dừng”.
  • Metadata tùy chọn truyền qua extra (ví dụ jackpot, payout…).

7. Troubleshooting & Tips​

  1. Embed không hiển thị → kiểm tra bạn có gọi .addEmbed() trên SmartMessage.
  2. Animated image không chạy → chắc chắn pool đúng định dạng và client hỗ trợ type 6.
  3. Update không thành công → đảm bảo embed được gửi bởi bot (không thể update message người dùng).
  4. Form input không hiện → ứng dụng Mezon phải hỗ trợ loại input tương ứng (text/select).

8. API Reference​

Phương thức chính​

setColor(color: string): EmbedBuilder
setTitle(title: string): EmbedBuilder
setURL(url: string): EmbedBuilder
setAuthor(name: string, options?: { icon_url?: string; url?: string }): EmbedBuilder
setDescription(description: string): EmbedBuilder
setDescriptionMarkdown(description: string | string[], options?: {
language?: string;
before?: string;
after?: string;
wrap?: boolean;
}): EmbedBuilder
setThumbnail(url: string): EmbedBuilder
setImage(url: string): EmbedBuilder
setTimestamp(timestamp?: Date | string): EmbedBuilder
setFooter(text: string, iconUrl?: string): EmbedBuilder
addField(name: string, value: string, inline?: boolean): EmbedBuilder
addTextField(name: string, inputId: string, options?: TextFieldOptions): EmbedBuilder
addSelectField(name: string, inputId: string, options: SelectOption[], selectedValue?: string): EmbedBuilder
addAnimatedImage(options: AnimatedImageOptions): EmbedBuilder
build(): IInteractiveMessageProps

Type Definitions​

interface TextFieldOptions {
placeholder?: string;
defaultValue?: string | number;
isNumber?: boolean;
}

interface SelectOption {
label: string;
value: string;
}

interface AnimatedImageOptions {
id?: string;
name?: string;
value?: string;
imageUrl: string;
positionUrl: string;
pool: string[][];
repeat?: number;
duration?: number;
isResult?: boolean;
extra?: Record<string, unknown>;
}

9. Ví dụ hoàn chỉnh: Poll Creator​

import {
Command,
AutoContext,
SmartMessage,
EmbedBuilder,
ButtonBuilder,
ButtonStyle,
} from '@n0xgg04/nezon';
import type { Nezon } from '@n0xgg04/nezon';

@Command('poll')
async function onPoll(@AutoContext() [managedMessage]: Nezon.AutoContext) {
await managedMessage.reply(
SmartMessage.build()
.addEmbed(
new EmbedBuilder()
.setColor('#E91E63')
.setTitle('POLL CREATOR')
.addTextField('Title', 'title', { placeholder: 'Input title here' })
.addTextField('Option 1️⃣', 'option_1', {
placeholder: 'Input option 1 here',
})
.addTextField('Option 2️⃣', 'option_2', {
placeholder: 'Input option 2 here',
})
.addSelectField(
'Type',
'type',
[
{ label: 'Single choice', value: 'SINGLE' },
{ label: 'Multiple choice', value: 'MULTIPLE' },
],
'SINGLE',
)
.addTextField('Expired Time (hour)', 'expired', {
placeholder: 'Input expired time here',
defaultValue: 168,
isNumber: true,
})
.setTimestamp()
.setFooter('Powered by Mezon', 'https://example.com/icon.jpg'),
)
.addButton(
new ButtonBuilder().setLabel('Cancel').setStyle(ButtonStyle.Danger),
)
.addButton(
new ButtonBuilder().setLabel('Add Option').setStyle(ButtonStyle.Secondary),
)
.addButton(
new ButtonBuilder().setLabel('Create').setStyle(ButtonStyle.Success),
),
);
}

10. Tài liệu liên quan​


id: embed-form-button title: Embed, Form, Button sidebar_position: 3


Hướng dẫn tạo rich embeds với EmbedBuilder, form inputs, và buttons.

EmbedBuilder​

EmbedBuilder cung cấp fluent API để tạo rich embeds (thẻ tin nhắn đẹp) với các field, ảnh, và form inputs.

Embed Example

Cú pháp cơ bản​

import { EmbedBuilder } from "@n0xgg04/nezon";

const embed = new EmbedBuilder()
.setColor("#abcdef")
.setTitle("Title")
.setDescription("Description")
.build();

Ví dụ đơn giản​

import { Command, AutoContext, SmartMessage, EmbedBuilder } from '@n0xgg04/nezon';
import type { Nezon } from '@n0xgg04/nezon';

@Command('embed')
async onEmbed(@AutoContext() [managedMessage]: Nezon.AutoContext) {
await managedMessage.reply(
SmartMessage.text('')
.addEmbed(
new EmbedBuilder()
.setColor('#abcdef')
.setTitle('Example Embed')
.setDescription('This is an example embed')
)
);
}

Description với Markdown / Code block​

await managedMessage.reply(
SmartMessage.text("").addEmbed(
new EmbedBuilder()
.setColor("#E91E63")
.setTitle(
"[SPECIALIZED (CHUYÊN NGÀNH)] The basic managerial skill(s) is(are)"
)
.setDescriptionMarkdown(
[
"1 - business strategy, human resource practices, organisational capabilities",
"2 - marketing strategy, human resource practices, organisational capabilities",
"3 - business strategy, human resource practices, organisational structure",
"4 - marketing strategy, human resource practices, organisational structure",
"5 - to supervise",
"6 - to stimulate",
"7 - to motivate",
"8 - all of the above",
],
{ after: "(Chọn đáp án đúng tương ứng phía bên dưới!)" }
)
)
);
  • setDescriptionMarkdown(content, options?) tự động wrap nội dung với triple backticks
  • content nhận string hoặc string[], auto join bằng xuống dòng
  • options.language đặt ngôn ngữ cho code block (ví dụ 'json')
  • options.before / options.after thêm text trước hoặc sau code block (tự thêm xuống dòng nếu thiếu)
  • options.wrap = false để bỏ qua code block wrapper và chỉ nối chuỗi thô

Embed Fields​

Thêm các field vào embed với addField().

Cú pháp​

addField(name: string, value: string, inline?: boolean): EmbedBuilder

Ví dụ​

@Command('embed')
async onEmbed(@AutoContext() [managedMessage]: Nezon.AutoContext) {
await managedMessage.reply(
SmartMessage.text('')
.addEmbed(
new EmbedBuilder()
.setColor('#abcdef')
.setTitle('User Info')
.addField('Username', 'john_doe', true)
.addField('Level', '42', true)
.addField('Status', 'Online', true)
.addField('Description', 'A long description that spans multiple lines', false)
)
);
}

Type​

addField(name: string, value: string, inline?: boolean): EmbedBuilder
// inline: true = hiển thị cùng hàng, false = hiển thị full width

Embed với Thumbnail và Image​

@Command('embed')
async onEmbed(@AutoContext() [managedMessage]: Nezon.AutoContext) {
await managedMessage.reply(
SmartMessage.text('')
.addEmbed(
new EmbedBuilder()
.setColor('#abcdef')
.setTitle('Rich Embed')
.setThumbnail('https://example.com/thumb.jpg')
.addField('Field 1', 'Value 1', true)
.addField('Field 2', 'Value 2', true)
.setImage('https://example.com/image.jpg')
.setFooter('Footer text', 'https://example.com/footer-icon.jpg')
)
);
}

Form Inputs trong Embed​

EmbedBuilder hỗ trợ thêm form inputs (text fields và select fields) vào embed.

Form Example

Text Field​

addTextField(
name: string,
inputId: string,
options?: {
placeholder?: string;
defaultValue?: string | number;
isNumber?: boolean;
}
): EmbedBuilder

Ví dụ Text Field​

@Command('form')
async onForm(@AutoContext() [managedMessage]: Nezon.AutoContext) {
await managedMessage.reply(
SmartMessage.build()
.addEmbed(
new EmbedBuilder()
.setColor('#E91E63')
.setTitle('POLL CREATOR')
.addTextField('Title', 'title', {
placeholder: 'Input title here',
defaultValue: '',
})
.addTextField('Option 1️⃣', 'option_1', {
placeholder: 'Input option 1 here',
})
.addTextField('Expired Time (hour)', 'expired', {
placeholder: 'Input expired time here',
defaultValue: 168,
isNumber: true,
})
)
);
}

Select Field​

addSelectField(
name: string,
inputId: string,
options: Array<{ label: string; value: string }>,
selectedValue?: string
): EmbedBuilder

Ví dụ Select Field​

@Command('form')
async onForm(@AutoContext() [managedMessage]: Nezon.AutoContext) {
await managedMessage.reply(
SmartMessage.build()
.addEmbed(
new EmbedBuilder()
.setColor('#E91E63')
.setTitle('POLL CREATOR')
.addSelectField('Type', 'type', [
{ label: 'Single choice', value: 'SINGLE' },
{ label: 'Multiple choice', value: 'MULTIPLE' },
], 'SINGLE')
)
);
}

Button với Embed​

Kết hợp buttons với embeds:

@Command('embed-button')
async onEmbedButton(@AutoContext() [managedMessage]: Nezon.AutoContext) {
await managedMessage.reply(
SmartMessage.text('')
.addEmbed(
new EmbedBuilder()
.setColor('#abcdef')
.setTitle('Action Required')
.setDescription('Please choose an option')
)
.addButton(
new ButtonBuilder()
.setLabel('Approve')
.setStyle(ButtonStyle.Success)
)
.addButton(
new ButtonBuilder()
.setLabel('Reject')
.setStyle(ButtonStyle.Danger)
)
);
}

Animated Image / Slots​

Sử dụng animated image để tạo hiệu ứng slot machine hoặc minigame:

import type { Nezon, NezonUtilsService } from '@n0xgg04/nezon';

@Command('slots')
async onSlots(
@AutoContext() [managedMessage]: Nezon.AutoContext,
@NezonUtils() utils: NezonUtilsService,
) {
const pool = [
['1.png', '2.png', '3.png'],
['4.png', '5.png', '6.png'],
['7.png', '8.png', '9.png'],
];

const ack = await managedMessage.reply(
SmartMessage.text('')
.addEmbed(
new EmbedBuilder()
.setColor('#1F8B4C')
.setTitle('🎰 Kết quả Slots 🎰')
.addAnimatedImage({
id: 'slots',
imageUrl: 'https://cdn.mezon.ai/.../slots.png',
positionUrl: 'https://cdn.mezon.ai/.../slots.json',
pool,
repeat: 3,
duration: 0.35,
}),
),
);

if (!ack?.message_id || !ack?.channel_id) {
return;
}

setTimeout(async () => {
const animatedMessage = await utils.getManagedMessage(
ack.message_id,
ack.channel_id,
);
if (!animatedMessage) {
return;
}
await animatedMessage.update(
SmartMessage.text('')
.addEmbed(
new EmbedBuilder()
.setColor('#1F8B4C')
.setTitle('🎰 Kết quả Slots 🎰')
.addAnimatedImage({
id: 'slots-result',
imageUrl: 'https://cdn.mezon.ai/.../slots.png',
positionUrl: 'https://cdn.mezon.ai/.../slots.json',
pool,
repeat: 3,
duration: 0.35,
isResult: true,
extra: {
jackpot: 1337517,
},
}),
),
);
}, 1300);
}
  • addAnimatedImage() tạo một field với inputs.type = 6 (animation).
  • pool là mảng 2D các frame để render animation cho từng cột (phải có asset thực tế).
  • repeat + duration điều khiển tốc độ/quãng quay (thay đổi quá nhanh sẽ khó đọc).
  • isResult = true báo client hiển thị frame cuối cùng; dùng extra để truyền metadata bổ sung (ví dụ jackpot, payouts, ...).
  • Nếu muốn transition giống utility slots, gửi animation trước rồi dùng managedMessage.update() (hoặc NezonUtils.getManagedMessage() + update()) để thay bằng embed kết quả sau ~1.3s.

EmbedBuilder API Reference​

Basic Methods​

setColor(color: string): EmbedBuilder
setTitle(title: string): EmbedBuilder
setURL(url: string): EmbedBuilder
setAuthor(name: string, iconUrl?: string, url?: string): EmbedBuilder
setDescription(description: string): EmbedBuilder
setDescriptionMarkdown(description: string | string[], options?: {
language?: string;
before?: string;
after?: string;
wrap?: boolean;
}): EmbedBuilder
setThumbnail(url: string): EmbedBuilder
setImage(url: string): EmbedBuilder
setTimestamp(timestamp?: Date | string): EmbedBuilder
setFooter(text: string, iconUrl?: string): EmbedBuilder
addAnimatedImage(options: AnimatedImageOptions): EmbedBuilder

Field Methods​

addField(name: string, value: string, inline?: boolean): EmbedBuilder
addTextField(name: string, inputId: string, options?: TextFieldOptions): EmbedBuilder
addSelectField(name: string, inputId: string, options: SelectOption[], selectedValue?: string): EmbedBuilder

Build​

build(): IInteractiveMessageProps

Type Definitions​

interface TextFieldOptions {
placeholder?: string;
defaultValue?: string | number;
isNumber?: boolean;
}

interface SelectOption {
label: string;
value: string;
}

interface AnimatedImageOptions {
id?: string;
name?: string;
value?: string;
imageUrl: string;
positionUrl: string;
pool: string[][];
repeat?: number;
duration?: number;
isResult?: boolean;
extra?: Record<string, unknown>;
}

Ví dụ hoàn chỉnh: Poll Creator​

import { Command, AutoContext, SmartMessage, EmbedBuilder, ButtonBuilder, ButtonStyle } from '@n0xgg04/nezon';
import type { Nezon } from '@n0xgg04/nezon';

@Command('poll')
async onPoll(@AutoContext() [managedMessage]: Nezon.AutoContext) {
await managedMessage.reply(
SmartMessage.build()
.addEmbed(
new EmbedBuilder()
.setColor('#E91E63')
.setTitle('POLL CREATOR')
.addTextField('Title', 'title', {
placeholder: 'Input title here',
defaultValue: '',
})
.addTextField('Option 1️⃣', 'option_1', {
placeholder: 'Input option 1 here',
})
.addTextField('Option 2️⃣', 'option_2', {
placeholder: 'Input option 2 here',
})
.addSelectField('Type', 'type', [
{ label: 'Single choice', value: 'SINGLE' },
{ label: 'Multiple choice', value: 'MULTIPLE' },
], 'SINGLE')
.addTextField('Expired Time (hour)', 'expired', {
placeholder: 'Input expired time here',
defaultValue: 168,
isNumber: true,
})
.setTimestamp()
.setFooter('Powered by Mezon', 'https://example.com/icon.jpg')
)
.addButton(
new ButtonBuilder()
.setLabel('Cancel')
.setStyle(ButtonStyle.Danger)
)
.addButton(
new ButtonBuilder()
.setLabel('Add Option')
.setStyle(ButtonStyle.Secondary)
)
.addButton(
new ButtonBuilder()
.setLabel('Create')
.setStyle(ButtonStyle.Success)
)
);
}

Best Practices​

  1. Luôn set color cho embed

    .setColor('#abcdef')
  2. Sử dụng inline fields cho thông tin ngắn

    .addField('Name', 'Value', true)
  3. Sử dụng full-width fields cho mô tả dài

    .addField('Description', 'Long text...', false)
  4. Kết hợp với buttons để tạo interactive UI

    SmartMessage.text('')
    .addEmbed(...)
    .addButton(...)

Xem thêm​