Module 5: Flex Messages
The most powerful message type — build rich, custom UIs using LINE's CSS-Flexbox-based layout system.
5.1 What is a Flex Message?
Flex Messages are fully customizable, structured message layouts using JSON that follows the CSS Flexbox model. Think of them as "rich cards" you can design — like building a mobile UI component inside a chat message.
Why Flex over Template messages?
- Template messages have fixed layouts (buttons, confirm, carousel)
- Flex messages let you control every pixel
- Flex supports nested layouts, custom colors, spacing, alignment
- Flex can include videos, icons, separator lines
- Template is being phased out; Flex is the future
Flex Message Simulator: LINE provides a Flex Message Simulator where you can preview your JSON without sending via API. Always test there first!
5.2 Flex Message Structure
{
"type": "flex",
"altText": "Fallback text shown in notifications",
"contents": {
"type": "bubble", // or "carousel"
"direction": "ltr", // or "rtl"
"header": { ... }, // Optional: top section
"hero": { ... }, // Optional: main image/video
"body": { ... }, // Optional: main content
"footer": { ... }, // Optional: bottom buttons
"styles": { ... } // Optional: global styling
}
}
Container types:
bubble— A single cardcarousel— Multiple swipable bubbles
Blocks (sections of a bubble):
| Block | Purpose |
|---|---|
header | Top banner area |
hero | Main image or video (full-width) |
body | Primary content area |
footer | Bottom area for buttons/actions |
5.3 Component Reference
| Component | Description | Key Properties |
|---|---|---|
box | Container (like div) — can be vertical or horizontal | layout, contents, spacing, margin, padding, backgroundColor |
text | Text element | text, size, color, weight, align, wrap, maxLines |
image | Image element | url, size, aspectRatio, aspectMode, backgroundColor |
button | Clickable button | action, style, height, color, gravity |
icon | Small icon image | url, size |
separator | Horizontal dividing line | color, margin |
filler | Spacer that fills remaining space | flex |
spacer | Fixed-size spacer | size (xs, sm, md, lg, xl, xxl) |
video | Video component (requires 2 taps) | url, previewImageUrl, aspectRatio, action |
Text size reference
| Size value | Font size |
|---|---|
xxs | 10px |
xs | 11px |
sm | 12px |
md | 13px |
lg | 16px |
xl | 19px |
xxl | 24px |
3xl | 32px |
4xl | 40px |
5xl | 48px |
5.4 Practical Examples
Example 1: Simple Product Card
{
"type": "flex",
"altText": "Product: Coffee Beans",
"contents": {
"type": "bubble",
"hero": {
"type": "image",
"url": "https://example.com/coffee.jpg",
"size": "full",
"aspectRatio": "20:13",
"aspectMode": "cover"
},
"body": {
"type": "box",
"layout": "vertical",
"spacing": "sm",
"contents": [
{
"type": "text",
"text": "☕ Premium Arabica Coffee",
"weight": "bold",
"size": "lg",
"wrap": true
},
{
"type": "box",
"layout": "baseline",
"contents": [
{ "type": "text", "text": "฿350", "weight": "bold", "size": "xl", "color": "#06c755" },
{ "type": "text", "text": "/bag", "size": "sm", "color": "#8c8c8c", "margin": "sm" }
]
},
{ "type": "separator", "margin": "md" },
{
"type": "text",
"text": "Single-origin from Doi Inthanon, Chiang Mai. Light roast with floral notes.",
"size": "sm",
"color": "#8c8c8c",
"wrap": true
}
]
},
"footer": {
"type": "box",
"layout": "vertical",
"spacing": "sm",
"contents": [
{
"type": "button",
"style": "primary",
"color": "#06c755",
"action": {
"type": "postback",
"label": "Add to Cart",
"data": "action=add&product=coffee-001"
}
},
{
"type": "button",
"style": "link",
"action": {
"type": "uri",
"label": "View Details",
"uri": "https://example.com/products/coffee-001"
}
}
]
}
}
}
Example 2: Restaurant Menu Carousel
{
"type": "flex",
"altText": "Today's Menu",
"contents": {
"type": "carousel",
"contents": [
{
"type": "bubble",
"hero": {
"type": "image",
"url": "https://example.com/pad-thai.jpg",
"size": "full",
"aspectRatio": "4:3",
"aspectMode": "cover"
},
"body": {
"type": "box",
"layout": "vertical",
"contents": [
{ "type": "text", "text": "Pad Thai", "weight": "bold", "size": "lg" },
{ "type": "text", "text": "฿89", "size": "md", "color": "#06c755" }
]
},
"footer": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "button",
"style": "primary",
"color": "#06c755",
"action": {
"type": "postback",
"label": "Order",
"data": "action=order&item=pad-thai"
}
}
]
}
},
{
"type": "bubble",
"hero": {
"type": "image",
"url": "https://example.com/tom-yum.jpg",
"size": "full",
"aspectRatio": "4:3",
"aspectMode": "cover"
},
"body": {
"type": "box",
"layout": "vertical",
"contents": [
{ "type": "text", "text": "Tom Yum Goong", "weight": "bold", "size": "lg" },
{ "type": "text", "text": "฿149", "size": "md", "color": "#06c755" }
]
},
"footer": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "button",
"style": "primary",
"color": "#06c755",
"action": {
"type": "postback",
"label": "Order",
"data": "action=order&item=tom-yum"
}
}
]
}
}
]
}
}
Example 3: Horizontal Layout with Icon + Text
{
"type": "flex",
"altText": "Contact Info",
"contents": {
"type": "bubble",
"body": {
"type": "box",
"layout": "vertical",
"spacing": "md",
"contents": [
{
"type": "box",
"layout": "horizontal",
"contents": [
{ "type": "icon", "url": "https://example.com/phone-icon.png", "size": "md" },
{
"type": "text",
"text": "02-123-4567",
"gravity": "center",
"flex": 1,
"margin": "sm"
}
]
},
{
"type": "box",
"layout": "horizontal",
"contents": [
{ "type": "icon", "url": "https://example.com/location-icon.png", "size": "md" },
{
"type": "text",
"text": "123/4 Sukhumvit Rd, Bangkok",
"gravity": "center",
"flex": 1,
"margin": "sm",
"wrap": true
}
]
},
{
"type": "box",
"layout": "horizontal",
"contents": [
{ "type": "icon", "url": "https://example.com/clock-icon.png", "size": "md" },
{
"type": "text",
"text": "Mon-Sun: 9:00 - 22:00",
"gravity": "center",
"flex": 1,
"margin": "sm"
}
]
}
]
}
}
}
5.5 Flex Layout Cheatsheet
| Property | Values | Description |
|---|---|---|
layout | horizontal, vertical, baseline | Direction of child elements in a box |
flex | 1, 2, 3, ... (positive integers) | Proportional space allocation (like flex-grow) |
gravity | top, center, bottom | Vertical alignment (for horizontal layout) |
align | start, center, end | Horizontal alignment (for vertical layout) |
margin | none, xs, sm, md, lg, xl, xxl | Margin on top of element |
spacing | Same as margin values | Gap between children in a box |
padding | Same as margin values | Padding of a box (all sides) |
position | relative, absolute | Positioning mode |
offsetTop/offsetBottom/offsetStart/offsetEnd | xs, sm, md, lg, xl, xxl, 3xl | Offsets when position is absolute |
wrap | true | Allow text to wrap (default: truncate) |
maxLines | 1-5 | Max lines before truncation (requires wrap: true) |
weight | regular, bold | Font weight |
style | normal, italic | Font style |
decoration | none, underline, line-through | Text decoration |
aspectRatio | e.g. 1:1, 16:9, 20:13, 4:3 | Image aspect ratio |
aspectMode | cover, fit | Image sizing mode |
button style | primary, secondary, link | Button visual style |
5.6 Flex Message Builder Workflow
- Design: Sketch your layout on paper or Figma
- Build JSON: Write the JSON structure manually or use a builder
- Simulate: Paste into Flex Message Simulator
- Iterate: Adjust sizes, colors, spacing
- Validate: Use the Validate API to check for errors
- Send: Include in your API call
Tools that help:
• Official Flex Message Simulator
• LINE Flex Builder — third-party visual builder
• Use template literals in code to inject dynamic data into Flex JSON
• Official Flex Message Simulator
• LINE Flex Builder — third-party visual builder
• Use template literals in code to inject dynamic data into Flex JSON
5.7 Validating Flex Messages
Always validate before sending to avoid errors:
POST https://api.line.me/v2/bot/message/validate/reply
{
"replyToken": "dummy",
"messages": [ YOUR_FLEX_MESSAGE_OBJECT ]
}
// Returns 200 OK if valid, or error details if invalid