Templating

Nunjucks

The templating language used for rendering the HTML is called Nunjucks. It is very similar to other templating languages like Twig, but is instead JavaScript based. It allows the use of conditional statements, loops, variables, includes, extends, ...

Make sure to check out the Nunjucks documentation to get a better understanding of awesomeness.

Structure

The Nunjucks is by default placed within the src/styleguide. This folder can be changed through the configuration of the project.

More information about the config and how to change the source folder can be found in the config section of the getting started manual.

Now then, let's start talking about the structure. This is very important! So try not to fall asleep.

The structure is fixed and is not customizable. This is done because the Express server looks at the structure and based on the folder structure creates the component-library. An example of a folder structure looks like this:

  • level 1: The source folder that contains basically everything

  • level 2: A type or name you give to a group of components. This can be anything you want, it just needs to encapsulate the type of components you place within. Important to know is that there are 2 names that are fixed:

  • fundamentals* and pages, but they can be changed within the configuration of the project.

  • level 3: The name you give to the component. This can be anything as well but should be a folder because it needs different types of files to render the component and their documentation correctly. The only exceptions are the fundamentals and pages folder.

  • styleguide - (level 1)

    • fundamentals - (level 2)
      • colors - (level 3)
      • typography - (level 3)
    • building-blocks - (level 2)
      • button - (level 3)
      • input - (level 3)
      • tag - (level 3)
    • components - (level 2)
      • collapse - (level 3)
      • header - (level 3)
      • footer - (level 3)
    • layouts - (level 2)
      • container - (level 3)
      • section - (level 3)
      • form - (level 3)
    • pages - (level 2)
      • home - (level 3)
      • about - (level 3)
      • contact - (level 3)

Fundamentals

At the moment the brandplatform only supports two types of fundamentals:

  • Colors
  • Typography

If you want to implement these settings you must create, in comparison to components, two files with an object in there with the same name mentioned above:

Colors

Place a variable called config in there, which is an object containing different keys. Each key is the category to which the colors belong too. Then you can add 2 types of colors:

  • a string with the color value in there (preferable #HEX)
  • an object with with 2 keys:
    • style: inline styling used to change the way the preview of the color looks. This is done to make sure you can see white blocks on a white background.
    • value: a string with the color value
{% set config = {
    primary: [
        "#0365F4"
    ],
    text: [
        "#000000",
        {
            style: "background-color: #FFFFFF; border: 1px solid #E9EAEB;",
            value: "#FFFFFF"
        },
        "#767676"
    ]
} %}

Typography

Place two objects to visualise the font-families and the different text-styles:

  • families: An array that contains objects with each two keys

    • name: The name you want to give the font

    • style: The inline styling that will be used to change the preview of the font-family

      {% set families = [
        {
            name: "Helvetica bold",
            style: "font-family: 'Helvetica'; font-weight: 700;"
        },
        {
            name: "Helvetica regular",
            style: "font-family: 'Helvetica'; font-weight: 400;"
        }
      ] %}
  • styles: An object that contains a key which represents the type of tag you want to add the style to. Each of these objects can contain any amount of keys and values. But the important thing is that these keys represents CSS-properties with their values. This is done so that the correct style is applied to the tag

      {% set styles = {
          h1: {
              "font-family": "Helvetica",
              "fontSize": "40px",
              "line-height": "50px",
              "font-weight": "700"
          },
          h2: {
              "font-family": "Helvetica",
              "font-size": "40px",
              "line-height": "50px",
              "font-weight": "700"
          }
      } %}

Building-blocks, components, ...

These folders are variable and unlike the fundamentals they do not contain any fixed values. You can add as many folders as you want or name them any way you want. The name will be used and rendered in the sidebar and can be used to generate components within those folders.

Each component can have different variations. These are different ways the component can be shown or presented. These can contain differentiations in modifiers or DOM. By default thre is already one variation called default.

The information about generating components can be found within the commands section of the getting started manual.

For example, if you run this command, a component header will be generated in the components folder. npm run generate -- --components=header

When generating or adding a component it will first generate a folder. This folder is called header, which is the name of the component passed in the command. In this folder different files are generated, lets take the header example, where the [name] is replaced by header.

_[name]-default.njk

The files within a component that have an _ (underscore) in front of them are used as variations of a component. The title, in this case, default is used as the title of the variation. This means that you can replace default by anything you want if you want to name your variation differently.

These variations consists out of imports and variables which will be used by the page to render the variation based on the contents of the variables. The name of these variables cannot be changed:

  • params: This contains any sort of parameters necessary to influence the variation, like a config for that variation specifically.

      {% set params = {
          styleVendors: [],
          scriptVendors: [],
          order: 1,
          scope: ""
      } %}
    • styleVendors: This is an array of the different style vendors that should be loaded in the <head> of the page
    • scriptVendors: This is an array of the different script vendors that should be loaded right before closing the </body>
    • order: A number used to order the variations, the higher the number the lower it is rendered in the list. The lower the number the higher it is rendered.
    • scope: An extra class you can pass to the preview of the variation to change the visual representation within the brandplatform. This is slicing that should only be part of the brandplatform, not of the components.
  • info: Optional information about the variation. This should be written in markdown.

  • preview: This is the component that we will see rendered within the preview window. This should simply be an execution of the macro within the [name]-macros.njk file, which is imported on top of the page. Here you can pass parameters to fill up the content of the component.

  • code: This is used to give a code-sample of the component. This is optional and if not used, the code from the preview variable is used to render the code sample. This should simply be an execution of the macro within the [name]-macros.njk file, which is imported on top of the page. Here you can pass parameters to fill up the content of the component.

By default a variation looks like this:

{# ========================================================================== #}
{# :: Imports #}
{# ========================================================================== #}
{% import "components/header/header-macros.njk" as header %}

{# ========================================================================== #} {# :: Settings #} {# ========================================================================== #} {% set params = { isFullWidth: false, styleVendors: [], scriptVendors: [], order: 1, scope: "" } %}

{# ========================================================================== #} {# :: Info #} {# ========================================================================== #} {# {% set info %}

{% endset %} #}

{# ========================================================================== #} {# :: Preview #} {# ========================================================================== #} {% set preview %}

{{header.default(&quot;&quot;, {})}}

{% endset %}

{# ========================================================================== #} {# :: Code #} {# ========================================================================== #} {# {% set code %}

{% endset %} #}

[name]-macros.njk

The macros file of the component is used to contain the markup. This is the only file that should contain code to structure the component. This file is a collection of macro's, which in Nunjucks are functions, that contain markup. Once the function is called, the markup is rendered where the function call is happening.

The macro file can have imports of other components that are used to render the component correctly. By default the macro file should look like this:

{# ========================================================================== #}
{# :: Imports #}
{# ========================================================================== #}

{# ========================================================================== #} {# :: Default #} {# ========================================================================== #} {% macro default(classes, data) %}

{% endmacro %}

As you can see above, these macro's are able to get parameters. We find that it is a good pattern to only pass two parameters to these macros:

  • classes: a string that is a list of classes that will be placed on the root of the structure within the macro

      {% macro default(classes, data) %}
          <header class="o-header {{classes}}">
          </header>
      {% endmacro %}
  • data: an object that has all the different keys used to fill up the content of the component. Even if there is just one key, this must stay an object for consistency. These keys are placed within the DOM to render for example copy.

      {% macro default(classes, data) %}
          <header class="o-header {{classes}}">
              <h1 class="o-header__title">{{data.title}}</h1>
    
    
          {% if data.text %}
              &lt;p class=&quot;o-header__text&quot;&gt;{{data.text}}&lt;/p&gt;
          {% endif %}
      &lt;/header&gt;

    {% endmacro %}

[name]-page.njk

The file used as the entry point of the component. This is a nunjucks file that mainly contains variables which can hold markdown. These are passed to the page rendering everything underneath and are rendered as markdown. The name of these variables cannot be changed:

  • info: Small block used to give an explanation to what a component is, what it does or what it contains. This is rendered on top of the page underneath the title and above the variations of the component.

  • modifiers: This variable is meant to hold a list of modifier-classes with their respective explanation. When adding markdown to this variable you must maintain the correct structure:

      * o-header--inverted
          A header that is inverted in colors where...
      * o-header--light
          A header in which the background color is...
  • states: This variable is meant to hold a list of state-classes with their respective explanation. When adding markdown to this variable you must maintain the correct structure:

      * is-open
          The headers state changes in which the navigation...
      * is-disabled
          The header is completely disabled, not being able to click...
  • javascript: This variable is meant to hold a list of javascript-classes with their respective explanation. When adding markdown to this variable you must maintain the correct structure:

      * js-hamburger
          The JavaScript is enabled on this component, making sure...
      * js-outline-text
          The Javascript is enabled on this component, rendering...

[name]-usage.njk

A markdown file where you can write down how to use this component, like do's or dont's. This file is optional. Keep in mind, you have to write Markdown in this file.

Pages

Pages contain the different views or interfaces that are build up with components and building-blocks defined in the previous chapters. There are two ways to structure the pages within the folder structure and these cannot be combined:

  • Using files: Directly place files in the pages folder, each file represents a page. A structure could look like this:

    • pages
      • home
      • about
      • contact
  • Using folders: Directly place folders in the pages folder, each folder represents a group of pages and each file within that folder is a page. A structure could look like this:

    • pages
      • general
        • home
        • about
      • booking
        • step 1
        • step 2
        • step 3
      • detail
        • article
        • booking

IMPORTANT TO KNOW is that pages have their very own logic and structure. The way this structure is build is a combination of folders starting with _ to make sure they are ignored by the express server and the pages structure as files or folders mentioned above. By default the folder structure there looks something like this (but more folders or files can be added):

  • pages
    • _base
      • default.njk
      • foot.njk
      • head.njk
    • _partials
      • home
        • hero.njk
        • ...
      • ...
    • home.njk
    • ...

_base

Contains all the starter templates of each page which are extendable and gives you the ability to define Nunjucks Placeholders to put the content of every page in.

default.njk

The default page should look very small and should only contain logic for reusability purposes in every other page.

<!DOCTYPE html>
<html lang="en">

{% include &quot;pages/_base/head.njk&quot; %}

&lt;body class=&quot;{{pageParams.bodyClass}}&quot;&gt;

    {{header.default()}}

    &lt;main&gt;
        {% block content %}
        {% endblock %}
    &lt;/main&gt;

    {{footer.default(pageParams.footerClass)}}

    {% include &quot;pages/_base/foot.njk&quot; %}

&lt;/body&gt;

</html>

foot.njk

The foot.njk file is mainly used to load everything necessary before the closing of the </body>. These are for example mainly scripts or script vendors.

head.njk

The head.njk file is mainly used to define the <meta> tags and other SEO related tags. The <link> to load in the CSS and their vendors should also be present.

_partials

The partials can be seen as parts of a page that are loaded in one after another to form a page. These should only contain markup, imports and execution of macro's. Each macro or loaded component should receive their data from these files. We do this to seperate the partials content and logic from each other and get a clear view of what belongs together.

A standard partial structure always has the name of the page the partials belong to as a parent folder in which the files are placed in:

  • _partials
    • home
      • hero.njk
      • article.njk
      • cta.njk
      • ...
    • about
      • intro.njk
      • content.njk
      • ...

home.njk, about.njk, contact.njk, ...

The page should make use of the files defined in the _base folder to load in the page template and fill in the placeholders to render everything in the correct place on the page. The content block for example should only consist out of includes of partials which have their own logic.

{# ========================================================================== #}
{# :: Inheritance #}
{# ========================================================================== #}
{% extends "pages/_base/default.njk" %}

{# ========================================================================== #} {# :: Settings #} {# ========================================================================== #} {% set pageParams = { bodyClass: "", styleVendors: [], scriptVendors: [] } %}

{# ========================================================================== #} {# :: Imports #} {# ========================================================================== #}

{# ========================================================================== #} {# :: Content #} {# ========================================================================== #} {% block content %}

{% include &quot;pages/_partials/home/intro.njk&quot; %}

{% endblock %}