Skip to content

Sections and Columns ​

The SectionBlock is the layout primitive in Templatical. Every multi-column layout is built by creating a section and placing blocks inside its columns.

Column layouts ​

Email best practice

Stick to 1-2 columns for most emails. Three-column layouts become cramped on mobile when columns stack vertically, and some email clients handle 3-column layouts inconsistently.

The columns property accepts one of five layout presets:

ValueDescriptionColumn widths
'1'Single column100%
'2'Two equal columns50% / 50%
'3'Three equal columns33% / 33% / 33%
'2-1'Two-thirds / one-third66% / 33%
'1-2'One-third / two-thirds33% / 66%
ts
type ColumnLayout = '1' | '2' | '3' | '2-1' | '1-2';

Creating sections ​

Use createSectionBlock from @templatical/types:

ts
import {
  createSectionBlock,
  createTitleBlock,
  createParagraphBlock,
  createImageBlock,
} from '@templatical/types';

// Empty two-column section
const section = createSectionBlock({ columns: '2' });

// Section with pre-populated columns
const hero = createSectionBlock({
  columns: '1-2',
  children: [
    [createImageBlock({ src: 'https://cdn.example.com/logo.png', width: 120 })],
    [
      createTitleBlock({ content: '<h1>Welcome</h1>', level: 1 }),
      createParagraphBlock({ content: '<p>Get started in minutes.</p>' }),
    ],
  ],
});

The children array ​

children is a Block[][] -- an array of arrays. Each inner array represents the blocks inside one column, ordered left to right.

ts
// For a '2' layout:
section.children = [
  [blockA, blockB],  // Left column
  [blockC],          // Right column
];

// For a '3' layout:
section.children = [
  [blockA],  // Left
  [blockB],  // Center
  [blockC],  // Right
];

The length of children must match the number of columns in the chosen layout. When you change columns, the editor automatically adjusts children -- merging excess columns into the last column or adding empty arrays for new columns.

Adding blocks to columns ​

To programmatically add a block to a specific column:

ts
// Add a button to the second column (index 1)
section.children[1].push(
  createButtonBlock({
    text: 'Learn More',
    url: 'https://example.com/docs',
  }),
);

Nesting ​

Sections cannot be nested inside other sections. Each section sits at the top level of the template's block list. Within a column, you can place any non-section block type: titles, paragraphs, images, buttons, tables, custom blocks, and so on.

Responsive behavior ​

On desktop, columns render side-by-side at their defined widths. On smaller screens, columns stack vertically in source order (left column on top) — MJML's default.

stackOnMobile opts out. Omit it or set true to keep stacking. false wraps the columns in <mj-group> so they stay side by side on mobile. The section toolbar exposes the toggle on multi-column sections. A one-column section never emits mj-group.

ts
const row = createSectionBlock({ columns: '2', stackOnMobile: false });

You can use the visibility property on individual blocks within columns to show or hide content per breakpoint:

ts
const block = createParagraphBlock({
  content: '<p>Desktop only sidebar content</p>',
});

block.visibility = {
  desktop: true,
  mobile: false,
};

See Styling for more on block visibility.

Section-level styles ​

Sections support the same BlockStyles as other blocks. Common use cases include setting a background color or padding on the entire row:

ts
const section = createSectionBlock({ columns: '1' });

section.styles = {
  backgroundColor: '#f8fafc',
  padding: { top: 32, right: 24, bottom: 32, left: 24 },
};

Sections also accept a borderRadius (in px, a section-specific property) for rounded corners — useful for a card-style section on a contrasting background:

ts
const card = createSectionBlock({ columns: '1', borderRadius: 12 });

card.styles.backgroundColor = '#ffffff';

Background image ​

A section's backgroundImage paints an image behind its columns. Set styles.backgroundColor as well, as the fallback while the image loads and in clients that don't show background images. In the editor's Background panel you also choose the size (Fill, Fit or Original), a nine-point position and whether the image repeats. See the Section block for the email client notes on background images.

Outer frame (wrapper) ​

To frame a section in a colored band — e.g. a white card sitting on a blue background — set wrapper. It renders an mj-wrapper around the section, with its own background, padding, and corner radius. The band is as wide as the email body (settings.width), not the recipient's whole window:

ts
const card = createSectionBlock({ columns: '1', borderRadius: 12 });
card.styles.backgroundColor = '#ffffff';

card.wrapper = {
  backgroundColor: '#1e3a8a',
  padding: { top: 24, right: 24, bottom: 24, left: 24 },
  borderRadius: 16,
};

The wrapper's padding is what makes the band show around the section. In the editor, enable it from the Wrapper panel in the section toolbar. The wrapper is a styling layer, not a container — sections still cannot be nested. An embedder-owned card around the authored sections is a layout overlay.