# Create a component from scratch

[BetaThis feature is new and we're actively working on it.](/beta-experimental-features/#beta-features)

In Design Studio, organize your code into reusable blocks with custom components.

 New to custom components?

If you’re new to custom components, check out how to [build them using visual blocks or our GPT](/journeys/create-custom-component/). This may save you some time!

## Understand the structure[](#understand-the-structure)

There are [two required tags](/journeys/custom-comp-syntax/#required-top-level-syntax) when setting up a component: `<script>` and `<template>`. The `<script>` tag is where you define properties for styles, slots for modifiable content, and other JavaScript logic. The `<template>` tag is where you create your content and reference variables and slots.

When you create a component from scratch, we provide the following code:

```html
<!-- 
  Insert this component in your email with the following code:
  
  <example-component></example-component>
-->
<script>
  export const config = { 
    label: "example component",
    presets: [
      {
        label: "example component",
        content: `<example-component></example-component>`
      }
    ]
  }

  // export const slots = Component.defineSlots({
  //   default: {
  //     schema: Component.slots.text(),
  //   },
  // });

  // export const props = Component.defineProps({
  // });
</script>
<template>
  <p>Content goes here</p>
</template>
```

In the `<script>` tag, use the `config` variable to define how the component is referenced in the visual and code editors - there are a number of [names and labels](#names-and-labels) to keep in mind.

We also include code that will help you get started defining [slots](/journeys/component-slots/) for modifiable, placeholder content and [properties](/journeys/component-properties/) for styles.

Learn more about optional [top-level elements](/journeys/custom-comp-syntax/#optional-top-level-syntax)—`<style>`, `<title>`, `<link>`, `<meta>`.

### Presets[](#presets)

Presets define the name of the component and what gets inserted into the editor.

`presets.label` is the name you’ll see in the insert menu.

When you drag a custom component into your message, we insert the value of `presets.content` into the code editor. With this template, we’d insert `<example-component></example-component>` into the code and render the content of the `<template>` in the final source code.

#### Hide from the insert menu[](#hide-from-the-insert-menu)

To hide a custom component from the Insert menu, delete the `presets` array of the `<script>` tag.

```html
  export const config = {
    "label": "My paragraph",
    presets: [
        {
          label: "My paragraph",
          content: `<my-paragraph></my-paragraph>`
        }
    ]
  }
```

You’ll still be able to add the custom component to the code editor and include the component as content in other component files.

Removing this label will not change any existing reference in your messages.

### Names and labels[](#names-and-labels)

In a component file, you’ll find a number of names and labels:

*   Filename - visible in the Design Studio dashboard, what we draw from to label your component when you first create the file.
*   Component Tag - located at the top of the component file.
    *   To define parent and child relationships, you’ll reference the component tag.
    *   Defines the name of the component tag visible in the code editor. **This must match the component tag name referenced in [`presets.content`](#understand-the-structure)**.
    *   The name can’t be an HTML element, like `h1`, or start with our standard component naming convention: `x-`.
*   `config.label` - appears in the Layers menu of the visual editor, also appears when you hover over the component on the canvas.
*   `presets.label` - appears in the Insert menu of the visual editor.

#### Component tag name validation[](#component-tag-name-validation)

Component tags follow the same rules as custom HTML elements with these additional restrictions:

*   Maximum 100 characters
*   Must start with a lowercase ASCII letter (`a`–`z`)
*   Must not start with a hyphen or a digit
*   Must not end with a hyphen
*   Must not contain uppercase letters
*   Must not contain consecutive hyphens (`-`)
*   May only contain lowercase letters, digits, and hyphens: `[a-z0-9-]`
*   Must not start with `x-` (reserved prefix)
*   Must not be a standard HTML element name (e.g. `div`, `span`, `table`)
*   Must not be a reserved Web Components spec name: `annotation-xml`, `color-profile`, `font-face`, `font-face-src`, `font-face-uri`, `font-face-format`, `font-face-name`, `missing-glyph`
*   Must not be a reserved Design Studio name: `context`, `fetch`, `slot`, `fragment`, `microlink`, `template`, `gretchen`, `component`, `email`, `scrape`

## How changes to a component file cascade to emails[](#how-changes-to-a-component-file-cascade-to-emails)

If you update a component file, those changes will cascade to your Design Studio messages. Whether you update the `<script>` or `<template>` of your component, changes cascade to references.

One caveat is the `presets` array. If you change `presets.content`, you must pull in the component again or directly modify the email to see the latest changes. Otherwise, any other change to definitions in your `<script>` or content in your `<template>` will immediately be reflected in your referenced messages.

 Publish changes to your emails after you update components

Updates first cascade to the message in Design Studio. Then you must click **Publish** to push those changes to connected campaigns, broadcasts, or transactional messages.

## Code your component[](#code-your-component)

When you create a custom component, you can decide how much control your teammates have over the content and styling in the visual editor.

### Add content[](#add-content)

By default, our out-of-the-box component code helps you build an uneditable block of reusable content—this might make sense for headers and footers to ensure consistency across emails.

You’ll add content—standard components, custom components, and/or HTML elements—to the `<template>` tag.

 You can use liquid directly in your components

Your component’s `<template>` has access to all the same liquid variables available in your emails—like `customer`, `event`, `trigger`, and `objects`. You don’t need to pass these as parameters; just use them directly in your template code. For example, `{{ customer.first_name }}` works in a component template the same way it does in an email. Learn more about [liquid in Design Studio](/journeys/liquid-visual-editor/).

[To create modifiable, placeholder content, you’ll add slots](/journeys/component-slots/). You can create slots that are text-based or drop-zones for other components.

### Add styles[](#add-styles)

By default, our out-of-the-box component code helps you build a block where styles are locked—this might make sense for headers and footers to ensure brand consistency across emails.

You can also code components so that after your teammates drag a custom component onto the visual editor, they can choose between specific styles you laid out in the code. To do this, define [properties](/journeys/component-properties/) in the `<script>` of your custom component.

Otherwise, you can hard-code inline styles in the `<template>` tag.

#### Create responsive styles[](#create-responsive-styles)

You can use [`@media` queries](https://developer.mozilla.org/en-US/docs/Web/CSS/@media) to define screenbreaks in a custom component or the `media` attribute.

For Thunderbird and other [email clients that don’t support `@media` queries](https://www.caniemail.com/features/css-at-media/), use the `media` attribute within an [isolated `<style>` tag](/journeys/component-styling/#isolate-styles).

#### Reference global styles[](#reference-global-styles)

You can use your global styles to define properties so your team stays on brand.

You’ll reference them using `globalStyles.<global-style-type>.<global-style-variablename-variableid>`. This might look like `globalStyles.colors.pink_khyqtq8v5rcs`.

 Use autocomplete to reference the global style

Note the variable id needed at the end of the global style reference. You can find this by using autocomplete in the component editor.

You can reference global styles in both properties and CSS to customize your components:

*   As an inline style—best for quick, one-off styles:
    
    ```html
      <div :style="`background: ${globalStyles.colors.pink_khyqtq8v5rcs};`">
    ```
    
*   [As a CSS class](/journeys/component-styling/#reference-global-styles) (make sure you use the `set()` function) while creating a stylesheet
*   [As a property value in a style object](/journeys/component-properties/#add-global-styles-to-properties)
*   As a variant for [select](/journeys/component-properties/#select) and [toggle](/journeys/component-properties/#toggle) properties—these property types let people in the visual editor choose the correct variant

### Define relationships between components[](#define-relationships-between-components)

You can define parent/child relationships between components such that team members using the visual editor can only drag/drop specific components into each other.

#### Parents[](#parents)

For instance, maybe you have a component `social-icons` that team members should only be able to insert into your `footer` component. In this case, the `config` code of the `social-icons` component should include `allowedParents`:

```html
<script>
  export const config = {
    "label": "social-icons",
    allowedParents: ['footer'],
    presets: [
        {
          label: "social-icons",
          content: `<social-icons></social-icons>`
        }
    ]
  };
</script>
```

#### Children[](#children)

If you want to specify that a component can only have certain child components, take advantage of [slots](/journeys/component-slots/), which let you create modifiable, placeholder content.

The `slots` code would include this, where you’d replace `social-icons` with any [**Component Tag Name**](#names-and-labels).

```html
<script>
  export const slots = Component.defineSlots({
      default: {
        schema: Component.slots.children(['social-icons']),
      },
  });
</script>
```

Check out [validation of slots](/journeys/component-slots/#allow-only-specific-components-to-be-inserted) for more info on child components.

## Troubleshooting issues[](#troubleshooting-issues)

If your component throws an error or fails to load after adding it to a Design Studio email, go to your component file and review your code. This often means you’ll need to resolve an issue with the `config`, `props` or `slots` definitions.

*   Make sure you define your [properties/variables](/journeys/component-properties/#validate-properties) and [slots](/journeys/component-slots/#define-your-slot) using:
    *   `Component.` notation in the `<script>`
    *   Only the schema we support
*   Make sure you define any custom properties in the `<script>`.
*   Ensure there’s both a `<script>` and `<template>` tag in your component file.
*   Make sure all code is within our [supported top-level elements](/journeys/custom-comp-syntax/).
*   Make sure the component tag name at the top of your component file matches the tag name used in `presets.content` in your `<script>`. For example, if your component tag name is “custom-footer”, then `presets.content` must include `<custom-footer></custom-footer>`.