Skip to content

Block Types

Templatical ships with 13 built-in block types. Every block extends a common Block base with shared properties (id, type, styles, displayCondition, mergeTag, customCss, visibility), and each type adds its own specific properties.

All block factories and type guards are exported from @templatical/types.

ts
import {
  createTextBlock,
  createImageBlock,
  createBlock,
  cloneBlock,
  isText,
  isImage,
} from '@templatical/types';

Text

Rich text content rendered as HTML.

PropertyTypeDefaultDescription
contentstring''HTML content
fontSizenumber16Font size in px
colorstring'#000000'Text color
textAlign'left' | 'center' | 'right''left'Horizontal alignment
fontWeightstring'normal'CSS font weight
fontFamilystringundefinedFont family override
ts
const block = createTextBlock({
  content: '<p>Welcome, {{name}}!</p>',
  fontSize: 18,
  textAlign: 'center',
});

Image

Displays an image with optional link wrapping.

PropertyTypeDefaultDescription
srcstring''Image URL
altstring''Alt text
widthnumber600Display width in px
align'left' | 'center' | 'right''center'Horizontal alignment
linkUrlstringundefinedWraps image in a link
linkOpenInNewTabbooleantrueLink target behavior
previewUrlstringundefinedPlaceholder shown in the editor
ts
const block = createImageBlock({
  src: 'https://cdn.example.com/hero.png',
  alt: 'Hero banner',
  width: 560,
  linkUrl: 'https://example.com',
});

Button

A call-to-action button with customizable appearance.

PropertyTypeDefaultDescription
textstring'Click me'Button label
urlstring''Link URL
backgroundColorstring'#007bff'Button background color
textColorstring'#ffffff'Button text color
borderRadiusnumber4Corner radius in px
fontSizenumber16Font size in px
buttonPaddingstring'12px 24px'Inner padding
fontFamilystringundefinedFont family override
openInNewTabbooleantrueLink target behavior
ts
const block = createButtonBlock({
  text: 'Get Started',
  url: 'https://example.com/signup',
  backgroundColor: '#6366f1',
  borderRadius: 8,
});

Divider

A horizontal line separator.

PropertyTypeDefaultDescription
lineStyle'solid' | 'dashed' | 'dotted''solid'Line style
colorstring'#cccccc'Line color
thicknessnumber1Line thickness in px
widthstring'100%'Line width
ts
const block = createDividerBlock({
  lineStyle: 'dashed',
  color: '#e5e7eb',
  thickness: 2,
});

Spacer

Empty vertical space.

PropertyTypeDefaultDescription
heightnumber20Height in px
ts
const block = createSpacerBlock({ height: 40 });

HTML

Injects raw HTML into the template. Use this for content that cannot be expressed with other block types.

PropertyTypeDefaultDescription
contentstring''Raw HTML markup
ts
const block = createHtmlBlock({
  content: '<div style="text-align:center;">Custom markup</div>',
});

Social Icons

A row of social media icons linking to platform profiles.

PropertyTypeDefaultDescription
iconsSocialIcon[][]List of social icons
iconStyle'solid' | 'outlined' | 'rounded' | 'square' | 'circle''solid'Visual style
iconSize'small' | 'medium' | 'large''medium'Icon size
spacingnumber8Space between icons in px
align'left' | 'center' | 'right''center'Horizontal alignment

16 platforms are supported: Facebook, Twitter/X, Instagram, LinkedIn, YouTube, TikTok, Pinterest, Snapchat, GitHub, Dribbble, Behance, Medium, Discord, Telegram, WhatsApp, and Reddit.

Each SocialIcon has:

ts
interface SocialIcon {
  platform: string;
  url: string;
  enabled: boolean;
}
ts
const block = createSocialIconsBlock({
  iconStyle: 'circle',
  iconSize: 'large',
  icons: [
    { platform: 'twitter', url: 'https://x.com/acme', enabled: true },
    { platform: 'github', url: 'https://github.com/acme', enabled: true },
  ],
});

A horizontal navigation menu with text links.

PropertyTypeDefaultDescription
itemsMenuItemData[][]Menu items
fontSizenumber14Font size in px
fontFamilystringundefinedFont family override
colorstring'#000000'Text color
linkColorstring'#007bff'Link color
textAlign'left' | 'center' | 'right''center'Alignment
separatorstring'|'Character between items
separatorColorstring'#cccccc'Separator color
spacingnumber8Space around separator

Each MenuItemData has:

ts
interface MenuItemData {
  text: string;
  url: string;
}
ts
const block = createMenuBlock({
  items: [
    { text: 'Home', url: 'https://example.com' },
    { text: 'Blog', url: 'https://example.com/blog' },
    { text: 'Docs', url: 'https://docs.example.com' },
  ],
  separator: '-',
});

Table

A data table with optional header row styling.

PropertyTypeDefaultDescription
rowsTableRowData[][]Table rows
hasHeaderRowbooleantrueStyle first row as header
headerBackgroundColorstring'#f3f4f6'Header row background
borderColorstring'#e5e7eb'Border color
borderWidthnumber1Border width in px
cellPaddingnumber8Cell padding in px
fontSizenumber14Font size in px
fontFamilystringundefinedFont family override
colorstring'#000000'Text color
textAlign'left' | 'center' | 'right''left'Cell text alignment
ts
const block = createTableBlock({
  hasHeaderRow: true,
  rows: [
    { cells: [{ content: 'Plan' }, { content: 'Price' }] },
    { cells: [{ content: 'Starter' }, { content: '$9/mo' }] },
    { cells: [{ content: 'Pro' }, { content: '$29/mo' }] },
  ],
});

Video

Displays a video thumbnail that links to the video URL. Since email clients do not support embedded video playback, a clickable thumbnail image is rendered instead.

PropertyTypeDefaultDescription
urlstring''Video URL (YouTube, Vimeo, etc.)
thumbnailUrlstring''Thumbnail image URL
altstring''Alt text for thumbnail
widthnumber600Display width in px
align'left' | 'center' | 'right''center'Horizontal alignment
openInNewTabbooleantrueLink target behavior
previewUrlstringundefinedEditor-only placeholder
ts
const block = createVideoBlock({
  url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
  thumbnailUrl: 'https://img.youtube.com/vi/dQw4w9WgXcQ/maxresdefault.jpg',
  alt: 'Product demo video',
});

Countdown

A live countdown timer that renders as digit groups with labels.

PropertyTypeDefaultDescription
targetDatestringISO date string for the countdown target
timezonestring'UTC'IANA timezone identifier
showDaysbooleantrueShow days digit
showHoursbooleantrueShow hours digit
showMinutesbooleantrueShow minutes digit
showSecondsbooleantrueShow seconds digit
separatorstring':'Character between digit groups
digitFontSizenumber32Digit font size in px
digitColorstring'#000000'Digit text color
labelColorstring'#666666'Label text color
ts
const block = createCountdownBlock({
  targetDate: '2026-12-31T23:59:59',
  timezone: 'America/New_York',
  showSeconds: false,
  digitFontSize: 48,
  digitColor: '#6366f1',
});

Section

A layout container that holds one or more columns. See Sections and Columns for full details.

PropertyTypeDefaultDescription
columnsColumnLayout'1'Column layout preset
childrenBlock[][][[]]Array of block arrays, one per column
ts
const block = createSectionBlock({
  columns: '2',
  children: [
    [createTextBlock({ content: '<p>Left column</p>' })],
    [createImageBlock({ src: 'https://cdn.example.com/photo.jpg' })],
  ],
});

Custom

A user-defined block type powered by field definitions and a Liquid template. See Custom Blocks for full details.

PropertyTypeDefaultDescription
customTypestringUnique identifier for the custom block type
fieldValuesRecord<string, any>{}Current values for defined fields
renderedHtmlstring''Cached rendered output
dataSourceFetchedbooleanfalseWhether the data source has been fetched
ts
const block = createCustomBlock({
  customType: 'product-card',
  fieldValues: {
    title: 'Wireless Headphones',
    price: 79.99,
    imageUrl: 'https://cdn.example.com/headphones.jpg',
  },
});

Utilities

Generic factory

Create any block by type string:

ts
import { createBlock } from '@templatical/types';

const block = createBlock('text'); // TextBlock with defaults

Cloning

Deep-clone a block with a new ID:

ts
import { cloneBlock } from '@templatical/types';

const copy = cloneBlock(existingBlock);
// copy.id !== existingBlock.id

Type guards

Narrow a Block union to a specific type:

ts
import { isText, isImage, isButton, isSection } from '@templatical/types';

if (isText(block)) {
  console.log(block.content); // TypeScript knows this is TextBlock
}

if (isImage(block)) {
  console.log(block.src);
}

Every block type has a corresponding guard: isText(), isImage(), isButton(), isDivider(), isSpacer(), isHtml(), isSocialIcons(), isMenu(), isTable(), isVideo(), isCountdown(), isSection(), isCustom().