Hybrid Output Mode

Hybrid mode generates <div>-based layouts for modern email clients with Outlook-specific <table> fallbacks wrapped in MSO conditional comments. This produces cleaner HTML, better accessibility, and smaller file sizes compared to pure table-based output.

Hybrid mode is off by default. The default output uses pure table-based markup for maximum compatibility.

Quick Start

# CLI flag
inky build src/ -o dist/ --hybrid # Or in inky.config.json
{"src": "src/emails", "dist": "dist", "hybrid": true}

How It Works

In table mode (default), a container outputs:

<table role="presentation" align="center" class="container"> <tbody><tr><td>...</td></tr></tbody>
</table>

In hybrid mode, the same container outputs:

<!--[if mso]><table role="presentation" width="580" align="center"><tr><td><![endif]-->
<div class="container" style="max-width:580px;margin:0 auto;">...</div>
<!--[if mso]></td></tr></table><![endif]-->

Modern email clients (Apple Mail, Gmail, Yahoo, etc.) use the <div> with CSS. Microsoft Outlook (which uses the Word rendering engine) sees the <table> inside the <!--[if mso]> conditional comments.

Supported Components

These layout components have hybrid variants:

Component Table Output Hybrid Output
<container> <table> <div> with max-width:580px + MSO table
<row> <table> with <tr> <div> with font-size:0 + MSO table row
<column> <th> with inner table <div> with display:inline-block + MSO <td>
<wrapper> <table> <div> + MSO table
<block-grid> <table> with <tr> <div> + MSO table

Other components (button, callout, spacer, etc.) use their standard table-based output in both modes.

Column Widths

In hybrid mode, columns use percentage-based widths calculated from the grid:

<row> <column lg="6">Left</column> <column lg="6">Right</column>
</row>

Produces (simplified):

<!--[if mso]><table width="100%"><tr><![endif]-->
<div class="row" style="font-size:0;"> <!--[if mso]><td width="50%" valign="top"><![endif]--> <div class="columns" style="display:inline-block;width:100%;max-width:50%;vertical-align:top;"> Left </div> <!--[if mso]></td><![endif]--> <!--[if mso]><td width="50%" valign="top"><![endif]--> <div class="columns" style="display:inline-block;width:100%;max-width:50%;vertical-align:top;"> Right </div> <!--[if mso]></td><![endif]-->
</div>
<!--[if mso]></tr></table><![endif]-->

CLI Usage

# Build with hybrid output
inky build email.inky --hybrid # Watch with hybrid output
inky watch src/ -o dist/ --hybrid # Serve with hybrid output
inky serve src/ --hybrid

Configuration

Add hybrid to inky.config.json:

{ "src": "src/emails", "dist": "dist", "hybrid": true
}

The --hybrid CLI flag overrides the config file.

Language Bindings

Node.js (WASM)

const inky = require("inky-wasm");
const html = inky.transformHybrid('<container><row><column>Hello</column></row></container>');

FFI (PHP, Python, Ruby)

import inky
html = inky.transform_hybrid('<container><row><column>Hello</column></row></container>')

When to Use Hybrid Mode

Use hybrid mode when:
- You want cleaner, more semantic HTML
- Accessibility is a priority (screen readers handle <div> better than nested tables)
- You need smaller file sizes (important for Gmail's 102KB clipping limit)
- Your audience primarily uses modern email clients

Stick with table mode when:
- You need maximum compatibility with older/niche email clients
- You're targeting environments where Outlook is the primary client (tables render more predictably in Outlook)
- You're migrating from v1 and want identical output behavior