Skip to content

Custom Fonts ​

By default, the editor includes a set of common web-safe fonts (Arial, Georgia, Verdana, etc.) in the font picker. You can extend this list with your own fonts — for example, loading custom typefaces from Google Fonts or your own CDN. When a custom font is used, it's automatically included as an <mj-font> declaration in the rendered MJML output.

Configure which fonts are available using the fonts option:

ts
import type { FontsConfig } from '@templatical/types';

const fonts: FontsConfig = {
  defaultFont: 'Inter',
  defaultFallback: 'Arial, sans-serif',
  customFonts: [
    {
      name: 'Inter',
      url: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap',
      fallback: 'Helvetica, Arial, sans-serif',
    },
    {
      name: 'Merriweather',
      url: 'https://fonts.googleapis.com/css2?family=Merriweather:wght@400;700&display=swap',
      fallback: 'Georgia, serif',
    },
  ],
};

const editor = await init({
  container: '#editor',
  fonts,
});

FontsConfig ​

PropertyTypeDescription
defaultFontstringFont name selected by default in new templates
defaultFallbackstringFallback stack used when a custom font is unavailable
customFontsCustomFont[]List of custom fonts to register
builtInsboolean | string[]Restrict which built-in fonts appear in the picker (see below)

CustomFont ​

PropertyTypeDescription
namestringDisplay name in the font picker
urlstringURL to the font CSS (e.g., Google Fonts link)
fallbackstringOptional fallback font stack for this font

Custom fonts are automatically included as <mj-font> declarations in the rendered MJML output.

Restricting the built-in fonts ​

By default the picker offers all seven built-in web-safe fonts (Arial, Helvetica, Georgia, Times New Roman, Verdana, Trebuchet MS, Courier New) alongside your customFonts. Use builtIns to narrow that list — useful when you embed the editor as a white-label / brand-kit tool and want authors to stay on approved typefaces.

ts
const fonts: FontsConfig = {
  // Keep only these built-ins, plus any customFonts:
  builtIns: ['Georgia', 'Arial'],
  // Or drop the built-ins entirely and offer only your custom fonts:
  // builtIns: false,
  customFonts: [
    /* ... */
  ],
};

Open in playground

  • true or omitted — all seven built-ins are offered (the default).
  • false — no built-ins; the picker lists only your customFonts.
  • string[] — an allowlist of built-in names to keep, matched case-insensitively. A name that isn't a built-in is logged with a warning and skipped.

Restricting the list doesn't change existing content. A custom font can still be the defaultFont when every built-in is excluded, and content already using a hidden built-in still renders with its proper fallback stack. Its picker shows that font too, so the select matches what the email renders: the block, the selected text or Template Settings lists it until the author picks an offered font, and it can't be chosen anywhere else.

If you exclude the family that new templates start on — Arial by default, or whatever you set as defaultFont — the editor logs a development warning at startup, because authors would land on a font the picker can't reselect. Either keep that family in builtIns, or set defaultFont to one you do offer.

Best practices ​

  • Always set a fallback — Most email clients don't support custom fonts. The fallback stack ensures your email still looks good when the custom font doesn't load.
  • Limit font weights — Only include the weights you actually need (e.g., wght@400;700). Extra weights increase load time for recipients.
  • Stick to 1-2 custom fonts — Too many fonts slow down rendering and make the design inconsistent. One for headings and one for body text is a common pattern.
  • Test across clients — Gmail, Outlook, and Apple Mail all handle fonts differently. Gmail supports Google Fonts in most cases, but Outlook falls back to system fonts.