Liquid Components

By default, templates in Bridgetown websites are powered by the Liquid template engine. You can use Liquid in layouts and HTML pages as well as inside of content such as Markdown text.

A key aspect of Bridgetown’s configuration of Liquid is the ability to render Liquid components. A component is a reusable piece of template logic (sometimes referred to as a “partial”) that can be included in any part of the site, and a full suite of components can comprise what is often called a “design system”.

Liquid components can be combined with front-end component strategies using web components or other JavaScript libraries/frameworks for a hybrid static/dynamic approach.

Table of Contents

Usage

Including a component within a content document or design template is done via a render tag or rendercontent tag. Here is a simple example:

Here is some **Markdown** text. Sign up for my newsletter!

{% render "forms/newsletter" %}

_Thank you!_

This would attempt to load the component defined in src/_components/forms/newsletter.liquid and render that into the document.

Here is a more complex example using a block and variables:

Really interesting content…

{% rendercontent "sections/aside", heading: "Some Additional Context", type: "important", authors: page.additional_authors %}
  Read what some of our panelists have to say about the matter.

  And **that's all folks**.
{% endrendercontent %}

### Wrapping Up

And in summary…

This would load the component in src/_components/sections/aside.liquid, which might look something like this:

{%- assign typeclass = "sidebar-default" %}
{%- if type == "important" %}
{%- assign typeclass = "sidebar-important" %}
{%- endif %}
<aside class="sidebar {{ typeclass }}">
  <h3>{{ heading }}</h3>
  {{ content }}
  <p class="authors">{{ authors | array_to_sentence_string }}</p>
</aside>

You can use components provided by others via plugins, or you can write your own components. You can also nest components within components. Here’s an example layout from this website used for our component previewing tool (more on that later):

{% rendercontent "shared/page_layout" %}
  {% rendercontent "shared/box" %}
    {% render "shared/back_to_button", label: "Components List", url: "/components/" %}
    {% render "shared/header_subpage", title: page.title %}

    <div class="content">
      {% render "component_preview/metadata", component: page.component %}
      {% render "component_preview/variables", component: page.component %}
    </div>
  {% endrendercontent %}
  {% render "component_preview/preview_area", page: page %}
{% endrendercontent %}

The “with” Tag

Instead of passing variable data to a block-style component inline with the rendercomponent definition, you can also use the with tag. This is great for components which combine a bunch of content regions into a single markup composition.

Here’s an example of how you might author a navbar component using with. First we’ll define the component itself:

<nav class="navbar">
  <div class="navbar-logo">
    {{ logo }}
  </div>

  <div class="navbar-start">
    {{ items_start }}
  </div>

  <div class="navbar-end">
    {{ items_end }}      
  </div>
</nav>

Now we can render that component and fill in the logo, items_start, and items_end regions:

{% rendercontent "navbar" %}
  {% with logo %}
    <a class="navbar-item" href="/">
      Awesome Site
    </a>
  {% endwith %}

  {% with items_start %}
    <a class="navbar-item" href="/">Home</a>
    <a class="navbar-item" href="/about">About</a>
    <a class="navbar-item" href="/posts">Posts</a>
  {% endwith %}

  {% with items_end %}
    <div class="navbar-item search-item">
      {% render "bridgetown_quick_search/search", placeholder: "Search", input_class: "input" %}
    </div>
    <a class="navbar-item is-hidden-desktop-only" href="https://twitter.com/{{ metadata.twitter }}" target="_blank" rel="noopener">
      <span class="icon"><i class="fa fa-twitter is-size-6"></i></span>
      <span class="is-hidden-tablet">Twitter</span>
    </a>
  {% endwith %}
{% endrendercontent %}

Normally content inside of with tags is not processed as Markdown (unlike the default behavior of rendercontent). However, you can add a :markdown suffix to tell with to treat it as Markdown. Example:

{% rendercontent "article" %}
  {% with title:markdown %}
    ## Article Title
  {% endwith %}

  Some _nifty_ content here.
{% endrendercontent %}

Rendering Liquid Components from Ruby-based Templates

You can use the liquid_render helper from Ruby-based templates to render Liquid components.

<%%= liquid_render "test_component", param: "Liquid FTW!" %>

If you pass a block to liquid_render, it will utilize the rendercontent Liquid tag and the block contents will be captured and made available via the content variable.

The Include Tag (Deprecated)

As part of Bridgetown’s past Jekyll heritage, you may be familiar with the include tag as a means of loading partials into templates and passing variables/parameters. This tag is now deprecated and will be removed once Bridgetown 1.0 is released later in 2021. The render tag offers greater room for performance optimizations and requires explicit declaration of available variables rather than relying on global variables—in other words, within a component file, you can’t access page or site, etc., unless you specifically pass page or site in as a variable. Example:

{% render "navbar", site: site %}

In many cases, you may not need to pass such large objects and can be more choosy in how you use variables. For example, maybe you can use site.metadata or page.url:

{% render "navbar", metadata: site.metadata, current_url: page.url %}

This will make testing and previewing this component easier in the future, because you’ll be able to define “mock” data for these variables.

Tips for migrating to render:

  • Files must not contain hyphens (-). Use underscores instead (_). So my_widget, not my-widget.
  • You don’t include extensions in the path. It automatically defaults to either .html or .liquid (preferred). So my_widget, not my_widget.html
  • As mentioned, any variables you use will have to be passed in explictly. No variables in the scope of a page or layout are available by default in a component.
  • The rendercontent block tag automatically converts anything you put inside of it from Markdown to HTML. So even in an HTML layout/page, if you have Markdown text inside the block, it will be converted.

Looking for previous documentation regarding the include tag?

Back to Components