Skip to content

Component Builder - Defining your Email Design System

In EmailShepherd, an Email Design System (EDS) is a collection of components that defines how your drag-and-drop email editor works.

Within your EDS, you:

  • Define reusable components that can be dragged and dropped into emails.
  • Specify editable fields that people using the email editor can customize (text, images, colors, etc.).
  • Write the HTML structure that determines how each component is rendered in emails.

This ensures brand consistency, makes emails easier to manage, and allows marketers to build emails without touching code.

The Component Builder is a development tool that lets you build, preview, and validate your Email Design System (EDS) in real time.

To start building your EDS:

  1. Navigate to Email Design Systems > New Email Design System.
  2. Enter a name and an optional description.
  3. Select whether you want to require a brand profile for this EDS. If a brand profile is required, one will need to be selected when creating emails with this EDS.
  4. Select the appropriate Access Scope for this EDS.
  5. Click Create, and you will be redirected to the Email Design System. From here you can enter Component Builder.

The left panel contains the code editor, where you’ll write the HTML for your components. On the right side of the screen you will see a metadata panel where you can see the fields you have defined and can add/edit/delete them.

Component Builder

You can also switch to a live preview view, which will show you a live preview of your components as you make changes to them.

Component Builder Live Preview

You can switch between components by clicking the dropdown in the control bar at the top of the screen.

If you have any unsaved changes, there will be an indicator in the top left of the screen.

A component is what people can drag / drop into the email editor.

It is made up of a template, and editable field definitions. It requires a label and name to be set; the label is what will be displayed in the component list in the email editor.

The component template is HTML that supports Liquid syntax, which allows you to reference the component’s editable fields.

Each field you define exposes a liquid variable, which you can reference in the template.

For example, if you have defined a text field with a liquid-variable of headline, you can reference it in the template with {{headline}}:

<table>
<tr>
<td>
<p>{{headline}}</p>
</td>
</tr>
</table>

Liquid is a powerful templating engine which will allow you to do more complex things, such as using Liquid filters, loops, and conditionals.

Fields:

labelliquid variabletype
Headlineheadlinetext
<!-- To ensure the title is capitalized -->
<p>{{headline | capitalize}}</p>

Fields:

labelliquid variabletype
Categoriescomma_separated_categoriestext
<!-- To loop through an array of items -->
<table>
{% assign categories = comma_separated_categories | split: ',' %}
{% for category in categories %}
<tr>
<td>{{category}}</td>
</tr>
{% endfor %}
</table>

Fields:

labelliquid variabletype
Titletitletext
Body textbody_texttext
CTA textcta_texttext
Show CTAshow_ctaboolean
<!-- for variations of your component, e.g. an optional CTA -->
<!-- assumes you have defined a title text field, a body_text text field, a cta_text text field, and a show_cta boolean field -->
<table>
<tr>
<td>
<p>{{title}}</p>
<p>{{body_text}}</p>
{% if show_cta %}
<a href="https://example.com">{{cta_text}}</a>
{% endif %}
</td>
</tr>
</table>

When managing your components, you have two options for removing them from active use:

Delete: Completely removes the component from the Email Design System. Any emails that currently use this component will no longer render it. The component is permanently removed and cannot be used in any emails. This includes from emails that are already published.

Deprecate: Marks the component as deprecated while keeping it in the Email Design System. Emails that already use the deprecated component will continue to work normally. However, the component will not appear in the component selector when building new emails or editing existing ones - preventing it from being added to emails in the future.

Use deprecate when you want to phase out a component gradually without breaking existing emails. Use delete when you’re certain the component should be completely removed and are prepared to handle any emails that currently use it.

Each Email Design System has a container component. This is a special component that is used as the shell for your email.

The Container Component’s template must include the {{children}} placeholder. This designates the drop zone — the area in the editor UI where users can drag and drop your components.

Fields defined in the Container Component are global fields. That means that:

  • they must be referenced using the global_fields prefix e.g. {{global_fields.your_field_name}}
  • they will be accessible to all other components in the Email Design System

In the email editor, container component fields (global fields) can be edited in the ‘Global fields’ section of the email editor.

An example of a basic Container Component’s template:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">
<meta name="x-apple-disable-message-reformatting">
<title>{{render_context.email.content.subject}}</title>
<style type="text/css">
/* Add your css */
</style>
</head>
<body style="background-color: {{global_fields.email_background_color}}">
<div style="display:none">
{{render_context.email.content.preheader}}
</div>
<table>
<tr>
<td>
<!-- Don't remove the children placeholder this is where components will be inserted -->
{{children}}
</td>
</tr>
</table>
</body>
</html>

A field corresponds to a property of a component that can be edited in the email editor UI. There are several types of fields, each of which will render a corresponding UI element in the UI editor.

You can create, edit or delete fields in the Component Builder UI.

Each field requires:

  • label - the label of the field, displayed in the UI editor
  • type - the type of the field, e.g. text, number, boolean, color, enum, image, rich_text, url
  • liquid-variable - the Liquid variable that can be referenced in the component’s HTML template

Each field also has some optional attributes:

  • hint - a tooltip displayed in the UI editor
  • visible-if - see the field visibility section

Some specific fields will also have additional attributes they require.

Each field type shows up as a specific kind of input in the editor — like a text box, toggle, or color picker.

The text field displays a simple text input field in the email editor.

Text Field

Fields:

labelliquid variabletype
CTA textcta_texttext
<table>
<tr>
<td>
<a href="https://example.com">{{cta_text}}</a>
</td>
</tr>
</table>

The number field displays a number input field in the email editor.

Its default-value must be a valid integer or float.

number Field

Fields:

labelliquid variabletype
Image widthimg_widthnumber
<table>
<tr>
<td>
<img src="https://example.com/example.png" width="{{img_width}}" style="display: block; width: {{img_width}}" />
</td>
</tr>
</table>

The boolean field displays a toggle in the email editor.

Its default-value must be either true or false.

boolean Field

Fields:

labelliquid variabletype
Show imageshow_imageboolean
<table>
<tr>
<td>
{% if show_image %}
<img src="https://example.com/example.png" />
{% endif %}
</td>
</tr>
</table>

The color field displays a color picker in the email editor.

Its default-value must be a valid HEX color value.

color Field

Fields:

labelliquid variabletype
Background colorbg_colorcolor
<table style="background-color: {{bg_color}}">
<tr>
<td>
<p>Some content</p>
</td>
</tr>
</table>

The enum field displays a dropdown menu with a list of predefined options in the email editor.

Its default-value must be one of the defined options.

enum Field

Fields:

labelliquid variabletypeoptions
Text alignmenttext_alignmentenumleft, center, right
<table style="text-align: {{text_alignment}}">
<tr>
<td>
<p>Some content</p>
</td>
</tr>
</table>

The image field displays a choice between uploading an image to the image library or enter a URL directly. You will generally want to use this as the src attribute of an <img> tag.

image Field

Fields:

labelliquid variabletype
Image URLimg_urlimage
<table>
<tr>
<td>
<img src="{{img_url}}" />
</td>
</tr>
</table>

The rich_text field displays a rich text editor in the email editor.

richText Field

Fields:

labelliquid variabletype
Texttextrich_text
<table>
<tr>
<td>
{{text}}
</td>
</tr>
</table>

The code field displays a code editor in the email editor.

code Field

Fields:

labelliquid variabletype
Code Blockcode_blockcode
<table>
<tr>
<td>
{{code_block}}
</td>
</tr>
</table>

You may wish to style the rich text fields in a certain way. To do this you can target as below:

descriptiontagcss class
Paragraph<p>es-paragraph
Bold<strong>es-bold
Italic<em>es-italic
Bullet list<ul>es-bullet-list
Ordered list<ol>es-ordered-list
List item<li>es-list-item
Link<a>es-link

The url field displays a text input field in the email editor with a button to preview the URL.

If a link tracking profile is configured, the user will be prompted to enter the configured tracking parameters for the link. Read more about link tracking profiles.

There is also an option to skip link tracking for this field by checking the Skip link tracking checkbox.

url Field

Fields:

labelliquid variabletype
CTA URLcta_urlurl
<table>
<tr>
<td>
<a href="{{cta_url}}">Click here</a>
</td>
</tr>
</table>

There are times where you may want to hide a field in the email editor. A simple example of this would be if one of your components has an optional image; you might have an image_src field, and a show_image boolean field. But if show_image is false, you probably don’t want to show the image_src field, e.g.:

Fields:

labelliquid variabletypevisible-if
Imageimage_srcurlshow_image == true
Show image?show_imageboolean
<table>
{% if show_image %}
<tr>
<td>
<img src="{{image_src}}" />
</td>
</tr>
{% endif %}
</table>

This can be achieved using the visible-if attribute of a field.

The visible-if attribute expects a valid Liquid expression. Just the expression part is needed, without the {% %} tags e.g. showImage == true or simply showImage.

You can use field groups to group together fields in the email editor. For example if you had a component featuring an image, you may choose to create a group called Feature image with an image field Source and a text field Alt Text.

Field Groups

Validation rules act as guardrails for your email design system, helping content creators stay within brand guidelines and quality standards. By adding validation rules to fields, you can enforce requirements like minimum/maximum character counts, or preventing blank fields. When a field fails validation, the editor provides immediate visual feedback, making it easy for users to identify and fix issues.

The image below shows an example of a field failing a validation rule:

Validation Error

There is also an indicator on the component itself:

Component Validation Error

Specific fields support different validation rules:

Field typeValidation ruleDescription
textMin LengthThe minimum length of the text in the field.
textMax LengthThe maximum length of the text in the field.
textMust Not Be BlankThe text must not be blank/empty.
textMust Not Be DefaultThe text cannot match the default value, it must be changed.
numberMinThe minimum value of the number.
numberMaxThe maximum value of the number.
imageMust Not Be BlankThe image must not be blank/empty.
imageMust Not Be DefaultThe image cannot match the default value, it must be changed.
codeMust Not Be BlankThe code must not be blank/empty.
codeMust Not Be DefaultThe code cannot match the default value, it must be changed.
urlMust Not Be BlankThe URL must not be blank/empty.
urlMust Not Be DefaultThe URL cannot match the default value, it must be changed.
urlMust Be a Valid URLThe URL must be a valid URL.
rich_textMin Content LengthThe minimum length of the rich text in the field. Note: the way this is calculated is with the HTML tags stripped from the value.
rich_textMax Content LengthThe maximum length of the rich text in the field. Note: the way this is calculated is with the HTML tags stripped from the value.
rich_textMust Not Be BlankThe rich text must not be blank/empty.
rich_textMust Not Be DefaultThe rich text cannot match the default value, it must be changed.

On every render EmailShepherd provides a render_context Liquid object whose properties can be referenced from within your EDS.

{
"render_context": {
"email": {
"id": 1,
"name": "My email",
"locale": "en-US",
"content": {
"subject": "Hello, world!",
"preheader": "This is a test email"
}
},
"project": {
"id": 1,
"name": "My project"
},
"email_design_system": {
"id": 1,
"name": "My email design system"
},
"brand_profile": {
"id": 1,
"name": "My brand profile"
},
"component_instance": {
"id": "abcd-1234-5678-9012",
"component_id": 1,
"name": "My component instance",
"component_name": "My component"
},
"connector": {
"id": 1,
"name": "My connector",
"type": "salesforce_marketing_cloud"
}
}
}

E.g. to reference the subject property from within your EDS, you can use {{render_context.email.content.subject}}:

<html>
<head>
<title>{{render_context.email.content.subject}}</title>
...
</head>
...
</html>

Design tokens are a powerful way to define reusable design values (like colors, spacing, typography, etc.) that can be used across all your components. They’re stored as a JSON object and are accessible via the render_context.design_tokens variable in your component templates.

Design tokens allow you to define brand-specific values in one central location rather than hardcoding them in each component. This makes it easy to:

  • Maintain consistency: Define values once, use them everywhere
  • Enable brand variations: Override tokens in brand profiles for multi-brand use cases
  • Update globally: Change a token value and all components using it are automatically updated

You can define design tokens in two places:

  1. Email Design System level: Click the “Design Tokens” button in the Component Builder to define tokens for your entire design system
  2. Brand Profile level: Click the “Design Tokens” button in the Brand Profile Builder to override design system tokens for specific brands

When both are defined, brand profile tokens are deep merged into the email design system tokens, with brand profile values taking precedence.

Here’s an example of a design tokens object:

{
"colors": {
"primary": "#007bff",
"secondary": "#6c757d",
"background": "#ffffff",
"text": "#212529"
},
"spacing": {
"small": "8px",
"medium": "16px",
"large": "24px",
"xlarge": "32px"
},
"typography": {
"font_family": "Arial, sans-serif",
"heading_size": "24px",
"body_size": "16px"
},
"border_radius": {
"button": "4px",
"card": "8px"
}
}

Once defined, you can reference design tokens in your component templates using Liquid syntax:

<table style="background-color: {{render_context.design_tokens.colors.primary}}">
<tr>
<td style="padding: {{render_context.design_tokens.spacing.medium}}">
<p style="font-family: {{render_context.design_tokens.typography.font_family}}; font-size: {{render_context.design_tokens.typography.body_size}}; color: {{render_context.design_tokens.colors.text}}">
Hello, world!
</p>
<a href="https://example.com" style="background-color: {{render_context.design_tokens.colors.primary}}; border-radius: {{render_context.design_tokens.border_radius.button}}; padding: {{render_context.design_tokens.spacing.small}} {{render_context.design_tokens.spacing.medium}};">
Click me
</a>
</td>
</tr>
</table>

If your Email Design System has these tokens:

{
"colors": {
"primary": "#007bff",
"secondary": "#6c757d"
}
}

And your Brand Profile overrides them with:

{
"colors": {
"primary": "#ff0000"
}
}

The final merged tokens available in templates will be:

{
"colors": {
"primary": "#ff0000",
"secondary": "#6c757d"
}
}