Module 5: Flex Messages

The most powerful message type — build rich, custom UIs using LINE's CSS-Flexbox-based layout system.

⏱ 35 min read 📖 Advanced

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 card
  • carousel — Multiple swipable bubbles

Blocks (sections of a bubble):

BlockPurpose
headerTop banner area
heroMain image or video (full-width)
bodyPrimary content area
footerBottom area for buttons/actions

5.3 Component Reference

ComponentDescriptionKey Properties
boxContainer (like div) — can be vertical or horizontallayout, contents, spacing, margin, padding, backgroundColor
textText elementtext, size, color, weight, align, wrap, maxLines
imageImage elementurl, size, aspectRatio, aspectMode, backgroundColor
buttonClickable buttonaction, style, height, color, gravity
iconSmall icon imageurl, size
separatorHorizontal dividing linecolor, margin
fillerSpacer that fills remaining spaceflex
spacerFixed-size spacersize (xs, sm, md, lg, xl, xxl)
videoVideo component (requires 2 taps)url, previewImageUrl, aspectRatio, action

Text size reference

Size valueFont size
xxs10px
xs11px
sm12px
md13px
lg16px
xl19px
xxl24px
3xl32px
4xl40px
5xl48px

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

PropertyValuesDescription
layouthorizontal, vertical, baselineDirection of child elements in a box
flex1, 2, 3, ... (positive integers)Proportional space allocation (like flex-grow)
gravitytop, center, bottomVertical alignment (for horizontal layout)
alignstart, center, endHorizontal alignment (for vertical layout)
marginnone, xs, sm, md, lg, xl, xxlMargin on top of element
spacingSame as margin valuesGap between children in a box
paddingSame as margin valuesPadding of a box (all sides)
positionrelative, absolutePositioning mode
offsetTop/offsetBottom/offsetStart/offsetEndxs, sm, md, lg, xl, xxl, 3xlOffsets when position is absolute
wraptrueAllow text to wrap (default: truncate)
maxLines1-5Max lines before truncation (requires wrap: true)
weightregular, boldFont weight
stylenormal, italicFont style
decorationnone, underline, line-throughText decoration
aspectRatioe.g. 1:1, 16:9, 20:13, 4:3Image aspect ratio
aspectModecover, fitImage sizing mode
button styleprimary, secondary, linkButton visual style

5.6 Flex Message Builder Workflow

  1. Design: Sketch your layout on paper or Figma
  2. Build JSON: Write the JSON structure manually or use a builder
  3. Simulate: Paste into Flex Message Simulator
  4. Iterate: Adjust sizes, colors, spacing
  5. Validate: Use the Validate API to check for errors
  6. 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

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