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.
<content>
tag if you're using Components as includes, and don't actually need to pass any content to them.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>
locals=''
must be a valid JSON string.locals=''
overrides the page
object, which will now be undefined
.