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