Components

Components are files that you can pull into a Template. You can pass data and content to them, and they help you organize blocks of markup that you use often.

Syntax

To create a Component, simply create an HTML file with a <content> tag:

<!-- src/components/example.html -->
<content></content>

The <content> tag is where content passed to the Component will be output.

To use a Component in a Template, you can use the <component> tag:

<component src="src/components/example.html">
  This text will replace the `content` tag in the Component.
</component>

Configuration

You can define where you keep your Components and what markup they use.

Attribute

Use a custom attribute name:

module.exports = {
  build: {
    components: {
      attribute: 'href',
    }
  }
}

You can now use it like this:

<component href="src/components/example.html">
  Content to pass inside component...
</component>

Tag

Use a custom tag name:

module.exports = {
  build: {
    components: {
      tag: 'module',
    }
  }
}

You can now use it like this:

<module src="src/components/example.html">
  Content to pass inside component...
</module>

Root

By default, when using a Component you have to reference its path relative to your project root (like we did above).

However, you can customize this path:

module.exports = {
  build: {
    components: {
      root: 'src/components',
    }
  }
}

Now you can reference them relative to that root path, and write less code:

<component src="example.html">
  Content to pass inside component...
</component>

Example

Let's create a VML background image Component, to which we can pass data about the image, and the HTML to be overlayed on top of it.

We might imagine something like this:

<!--[if mso]>
<v:image src="{{ page.image.url || 'https://via.placeholder.com/600x400' }}" xmlns:v="urn:schemas-microsoft-com:vml" style="width:{{ page.image.width || 600 }}px;height:{{ page.image.height || 400 }}px;" />
<v:rect fill="false" stroke="false" style="position:absolute;width:{{ page.image.width || 600 }}px;height:{{ page.image.height || 400 }}px;">
<v:textbox inset="0,0,0,0"><div><![endif]-->
<content></content>
<!--[if mso]></div></v:textbox></v:rect><![endif]-->

The content of the Component or, in our case, the HTML to be overlayed, will be output in place of the <content> tag.

The variables that we are referencing from the page object are currently undefined, so we let's create them in Front Matter:

---
image:
  url: https://example.com/image.jpg
  width: 600
  height: 400
---

<extends src="src/layouts/master.html">
  <block name="template">
    <component src="src/components/my-component.html">
      <div>
        Overlayed HTML!
      </div>
    </component>
  </block>
</extends>

Result:

<!--[if mso]>
<v:image src="https://example.com/image.jpg" xmlns:v="urn:schemas-microsoft-com:vml" style="width:600px;height:400px;" />
<v:rect fill="false" stroke="false" style="position:absolute;width:600px;height:400px;">
<v:textbox inset="0,0,0,0"><div><![endif]-->
  <div>
    Overlayed HTML!
  </div>
<!--[if mso]></div></v:textbox></v:rect><![endif]-->

Variables

When creating a Component, you have access to the page object:

<!-- src/components/example.html -->
<div>
  The current build environment is: {{ page.env }}
</div>

However, if you need to pass variables as content to a Component, like this:

<component src="src/components/vmlbg.html">
  Current build environment is: {{ page.env }}
</component>

... you also need to enable the initial option in the Component config:

module.exports = {
  build: {
    components: {
      initial: true,
    }
  }
}

When set to true, this will apply plugins to the root file as well, and expressions will be evaluated when passed as content to a Component. This is disabled by default, as it re-applies PostHTML plugins to the file, which can sometimes cause issues.

You can also manually provide data to the Component instead, in the form of a JSON string that you pass inside a locals attribute:

<extends src="src/layouts/master.html">
  <block name="template">
    <component src="src/components/vmlbg.html" locals='{"foo": "bar"}'>
      <div>
        Foo is {{ foo }}
      </div>
    </component>
  </block>
</extends>