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 only affects the picker. 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.

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.