MJML component that prevents columns from stacking on mobile devices by maintaining side-by-side layout in responsive emails
npx @tessl/cli install tessl/npm-mjml-group@4.15.0MJML Group is a component for the MJML email framework that prevents columns from stacking on mobile devices. It maintains side-by-side column layouts in responsive emails, essential for complex multi-column email designs that need to preserve their structure across desktop and mobile email clients.
npm install mjml-group// ES Modules
import MjGroup from "mjml-group";
// CommonJS
const MjGroup = require("mjml-group");MJML Group is used within MJML templates to wrap columns that should remain side-by-side on mobile:
<mjml>
<mj-body>
<mj-section>
<mj-group width="100%" background-color="#f0f0f0">
<mj-column width="50%">
<mj-text>Left column content</mj-text>
</mj-column>
<mj-column width="50%">
<mj-text>Right column content</mj-text>
</mj-column>
</mj-group>
</mj-section>
</mj-body>
</mjml>MJML Group extends the MJML BodyComponent base class and integrates with the MJML ecosystem:
mj-group tagThe main component class that handles group rendering and responsive behavior.
/**
* MJML Group component class extending BodyComponent
* Prevents columns from stacking on mobile devices
*/
class MjGroup extends BodyComponent {
static componentName: string;
static allowedAttributes: {
'background-color': string;
direction: string;
'vertical-align': string;
width: string;
};
static defaultAttributes: {
direction: string;
};
}Static properties defining the component's behavior and allowed attributes.
/**
* MJML component tag name
*/
static componentName: "mj-group"
/**
* Allowed MJML attributes with validation types
*/
static allowedAttributes: {
'background-color': 'color',
'css-class': 'string',
direction: 'enum(ltr,rtl)',
'vertical-align': 'enum(top,bottom,middle)',
width: 'unit(px,%)'
}
/**
* Default attribute values
*/
static defaultAttributes: {
direction: 'ltr'
}Methods for managing child component context and width calculations.
/**
* Calculates and returns context for child components
* @returns {Object} Child context with container width and sibling information
*/
getChildContext(): {
...parentContext,
containerWidth: string;
nonRawSiblings: number;
}Methods for generating CSS styles and responsive classes.
/**
* Generates CSS styles for the group component
* @returns {Object} CSS styles object with div and tdOutlook properties
*/
getStyles(): {
div: {
'font-size': string;
'line-height': string;
'text-align': string;
display: string;
width: string;
direction: string;
'vertical-align': string;
'background-color': string;
};
tdOutlook: {
'vertical-align': string;
width: string;
};
}
/**
* Generates CSS class name for responsive media queries
* @returns {string} CSS class name (e.g., "mj-column-per-50" or "mj-column-px-300")
*/
getColumnClass(): stringMethods for handling responsive width calculations in different units.
/**
* Parses width attribute and returns width information
* @param {boolean} toString - Whether to return formatted string or object
* @returns {string|Object} Width value as string or parsed width object
*/
getParsedWidth(toString?: boolean): string | {
unit: string;
parsedWidth: number;
}
/**
* Converts current width to pixel value regardless of original unit
* @returns {string} Width in pixels (e.g., "300px")
*/
getWidthAsPixel(): stringMain rendering method that generates the final HTML output.
/**
* Renders the group component to HTML with Outlook conditional comments
* @returns {string} HTML string output with responsive behavior
*/
render(): stringMJML Group inherits additional methods from BodyComponent:
/**
* Retrieves attribute value by name
* @param {string} name - Attribute name
* @returns {any} Attribute value
*/
getAttribute(name: string): any
/**
* Retrieves shorthand attribute values (e.g., padding, margin)
* @param {string} attribute - Base attribute name
* @param {string} direction - Direction (top, right, bottom, left)
* @returns {number} Parsed attribute value
*/
getShorthandAttrValue(attribute: string, direction: string): number
/**
* Calculates width values for layout calculations
* @returns {Object} Width information including totalWidth, borders, paddings, box
*/
getBoxWidths(): {
totalWidth: number;
borders: number;
paddings: number;
box: number;
}
/**
* Generates CSS styles string from style object or style name
* @param {string|Object} styles - Style object or style property name
* @returns {string} CSS styles as string
*/
styles(styles: string | Object): string
/**
* Formats attributes for HTML output
* @param {Object} attributes - Attributes object
* @returns {string} Formatted HTML attributes string
*/
htmlAttributes(attributes: Object): string
/**
* Renders child components within the group
* @param {Array} children - Child components array
* @param {Object} options - Rendering options
* @returns {string} Rendered children HTML
*/
renderChildren(children: Array, options: Object): stringWhen used in MJML templates, mj-group supports these attributes:
<!-- Group width in pixels or percentage -->
<mj-group width="50%" />
<mj-group width="300px" />
<!-- Vertical alignment of group content -->
<mj-group vertical-align="top" /> <!-- default -->
<mj-group vertical-align="middle" />
<mj-group vertical-align="bottom" />
<!-- Background color -->
<mj-group background-color="#f0f0f0" />
<mj-group background-color="red" />
<!-- Text direction -->
<mj-group direction="ltr" /> <!-- default -->
<mj-group direction="rtl" />
<!-- Custom CSS class -->
<mj-group css-class="custom-group" />Basic Side-by-Side Layout:
<mj-section>
<mj-group>
<mj-column width="50%">
<mj-text>Left content</mj-text>
</mj-column>
<mj-column width="50%">
<mj-text>Right content</mj-text>
</mj-column>
</mj-group>
</mj-section>Styled Group with Background:
<mj-section>
<mj-group width="80%" background-color="#e8f4f8" vertical-align="middle">
<mj-column width="60%">
<mj-text>Main content area</mj-text>
</mj-column>
<mj-column width="40%">
<mj-image src="image.jpg" />
</mj-column>
</mj-group>
</mj-section>Mixed Groups and Columns:
<mj-section>
<!-- Regular column that will stack on mobile -->
<mj-column>
<mj-text>Header content</mj-text>
</mj-column>
<!-- Group that maintains side-by-side layout on mobile -->
<mj-group>
<mj-column width="50%">
<mj-text>Left sidebar</mj-text>
</mj-column>
<mj-column width="50%">
<mj-text>Right sidebar</mj-text>
</mj-column>
</mj-group>
</mj-section>