Custom Components

To define a custom component, you need to create a component template file in the /components directory and declare it in the template.config.js file.

Component structure

A component consists of three parts - html template, styles and scripts. Those are all defined in the same template file.

Let's say you want to have a single reusable image, then you can create a my-image.html file in the components directory with the following content:

<!-- /components/my-image.html -->
<template>
   <img src="https://placekitten.com/300/200" class="my-image">
</template>
<style>
.my-image {
   border: 1px solid red;
   
   &:hover {
      border-color: blue;
   }
}
</style>
<script>
const images = [].slice.call(document.querySelectorAll('.my-image'));
images.forEach((img, idx) => {
   img.addEventListener('click', () => { console.log(idx); });
});
</script>

If you don't need any custom scripts or styles for you component, you can just put the image markup into the component file:

<!-- /components/my-image.html -->
<img src="https://placekitten.com/300/200" class="my-image">

Then you'd just need to add a components configuration array to the template.config.js file:

// template.config.js
module.exports = {
   name: 'My first template',
   components: [
      { name: 'my_image', src: 'my-image.html' }
   ]
}

The component can then be rendered inside of any other template using the component macro:

{{@component(my_image)}}

Static components

Static components are reusable parts of code which can be used in your template parts, and/or inserted into a page/post.

Dynamic components

Dynamic components have to be instantiated before they can be added into a post/page. Let's say we want to create image gallery that can be reused across different posts.

First we'll create a gallery.html file in the /components directory with the following content:

<!-- /components/gallery.html -->
<div class="gallery">
   <h3 class="gallery__title">{{title}}</h3>
   <!-- iterate over the images list and render an image macro -->
   <ul class="gallery__images">
      {{#images}}
         <li class="gallery__image">
            {{@image(value, maxWidth=150)}}
         </li>
      {{/images}}
   </ul>
</div>

To make the component instantiable, it needs to be connected in the template.config.js file, and the props the component will receive have to be defined:

// template.config.js
module.exports = {
   name: 'My first template',
   components: [
      { 
         name: 'gallery', 
         src: 'gallery.html',
         viewName: 'Gallery',
         editorComponent: true,
         props: [
            { name: 'title', viewName: 'Title', type: 'text' },
            { name: 'images', viewName: 'Images', type: 'list', itemType: 'image' }
         ]
      }
   ]
};

Component declaration

A single component can be configured using the following settings:

  • name (required) - the name of the component, used for rendering or cross-referencing

  • viewName - the view name of the component, will be displayed in the Phaistos editor

  • src (required) - the name of the html file in the components directory

  • editorComponent - whether this component can be inserted in the content editor (false by default)

  • props - an array of props the instantiated component will receive

Prop types

Any dynamic component can receive the following props: