Docs (Public)

Components (often called includes or partials) are stored inside the components folder. Like layout files, components are written in Nunjucks. You can include a component from any layout (or another component) by using Nunjucks include tag:

{% include "footer.html" %}

In Unibit the site and page Variables are passed to the include. Take the following example, where the params button_url and button_text are available in a component called button.html

# config.yaml

baseurl: "/"
title: "Universal"
# content/index.md

---
title: Home
layout: home
heading: "A Unibit Starter Theme"
show_button: true
button_url: https://docs.stackbit.com/unibit/
button_text: "Unibit Documentation"
---

Unibit is a superset of existing static site generators. It can be used as a standalone ssg or it can be imported into [Stackbit](https://www.stackbit.com) and seamlessly converted into other static site generators and headless CMS.
<!-- layouts/home.html -->

{% extends "body.html" %}

{% block content %}
<div class="home">
  <h1>{{ page.params.heading }}</h1>
  {% include "button.html" %}
</div>
{% endblock %}
<!-- components/button.html -->

<div class="button-container">
 <a href="{{ page.params.button_url }}" class="button">
    <strong>{{ site.title }}</strong> {{ page.params.button_text }} 
</a>
</div>

Passing Scoped Variables

components accept scoped variables.

Passing a new scoped variable

{% set include_dict = {"classes": "button button-primary"} %}
{% include "button.html" %}
<!-- components/button.html -->

<button class={{ include_dict.classes }}>text</button>

Passing scoped variables and existing global variables

Its important to note that if you decide to pass a new scoped variable to a component then that component no longer has access to the context of the global variables site, page and menu

In the previous example, access to page.params.button_url would no longer exist. If you are using scoped variables you must explicitly redeclare any special variable keys you need.

{% set include_dict = {"classes": "button button-primary", "site": site, "page": page } %}
{% include "button.html" %}
<!-- components/button.html -->

<div class="button-container">
 <a href="{{ include_dict.page.params.button_url }}" class="{{ include_dict.classes }}">
    <strong>{{ include_dict.site.title }}</strong> {{ include_dict.page.params.button_text }} 
</a>
</div>

Passing special variables using scoped variables

The following naming rules must be used when passing special variables:

  • key must be site when, and only when, passing the global site object
  • key must be page when, and only when, passing the global page object
  • key must be <name>_page when, and only when, passing page object other than global page object
  • key must be <name>_pages when, and only when, passing list of page objects
  • key must be paginator when, and only when, passing the paginator object
  • key must be menu when, and only when, passing a menu object from site.menus.<menu_name> or a site.menus.<menu_name>[index].children object

Including Components Dynamically

Sometimes the components to be included in the template are not known in advance but determined when the template is executed. In these cases, the special component_file filter can be used.

The following example demonstrates how a page could define a list of sections represented by different components.

# content/index.md
---
title: Home
layout: home
sections:
  - type: section_hero
    title: I am a Hero
    subtitle: Lorem ipsum dolor sit amet.
    img: /images/hero-image.png
  - type: section_cta
    title: Call to Action Title
    label: Click Me!
    url: http://www.example.com
  - type: section_text
    text: Sed at libero in turpis scelerisque eleifend quis in massa.
    background_color: blue
---

Assuming there are components for each of these sections named after the type attribute:

├── components
│   ├── section_hero.html
│   ├── section_cta.html
│   ├── section_text.html
│   └── ...

Using the component_file filter, tThe home layout template could be written as:

{# layouts/home.html #}

{% extends "body.html" %}

{% block content %}

{% for section in page.params.sections %}
  {% set component = section.type | component_file %}
  {% set include_dict = {'section': section, 'site': site} %}
  {% include component %}
{% endfor %}

{% endblock %}

Note: under the hood, the component_file filter just appends .html to the provided value. But it is important to use this filter and not concatenating section.type with .html manually as it won't work when a theme will be imported into Stackbit and converted into different SSG. The parameter specifying the name of the component (e.g.: type) must not include the .html extension for this filter to work correctly.

Required Components

Two component file names are required for customizing the internal base.html layout.

  • html_head.html - content that will be placed inside the <head> tags
  • post_body.html - the content of this component will be included at the bottom of the page above the closing </body> tag.

These components are required by the base.html which is an internal Unibit file and has the following structure:

<!-- base.html -->

<!doctype html>
<html>
    <head>
        {% include "html_head.html" %}
    </head>
    <body>
        {% block body %}{% endblock %}
        {% include "post_body.html" %}
    </body>
</html>

Read more about these components in Layouts