Menu

Creating a component

Once you've established a new pattern is required, it's time to create a new component. For the purpose of this tutorial, let's assume the component is called Filter Bar.

First of all, create a directory to house the component: src/_includes/components/filter-bar

Note, use kebab-case for directory & file names.

Next up, a few files will need to be created in that new folder:

  • filter-bar.njk - The component code
  • macro.njk - The wrapper around the component
  • filter-bar.scss - Optional: For styling the component
  • filter-bar.config.js - Optional: For rendering the component in Project Franklin
  • filter-bar.md - Optional: For documenting the component

filter-bar.njk

Variables passed to this file can be accessed via the params variable. Other than that, this is a totally encapsulated file, with no access to global variables. Here's a very basic component that outputs the title parameter:

<div class="mp c-filter-bar">
<h2 class="c-h c-h--step-2">{{ params.title }}</h2>
</div>

You can also include other components inside this one. You can import it via the other component's macro, then call it like a function:

{%- from "components/icon/macro.njk" import icon -%}

<div class="mp c-filter-bar">
<h2 class="c-h c-h--step-2">{{ params.title }}</h2>
{{ icon({
id: 'twitter'
}) }}
</div>

These components aren't being included directly into application code, but will be used for reference, so think through the component composition and create sensible logic that can be recreated in Razor, DXA, PHP and any other language this is converted to. Read more about Nunjuck templating.

macro.njk

Every component has a corresponding macro file, allowing us to instantiate a component in a totally encapsulated area. The macro itself uses another .njk file to render the component, allowing us to render the component in the same way within Project Franklin.

{%- from "components/component/component.njk" import c -%}

{%- macro filterBar(params) -%}
{{ c({ name: 'filter-bar' }, params) }}
{%- endmacro -%}

Note, use camelCase for the macro name.

This c component takes two parameters:

  1. Component object with three parameters
    1. name: a string matching the .njk file name
    2. folder: Optional: by default, the same as the name
    3. root: Optional: by default, ../, effectively the src/_includes/components directory
  2. The params object, passed in from the macros own parameters

filter-bar.scss

This SCSS file has access to all the mixins, functions and foundational elements documented in Project Franklin. To add it to the main bundle, head to src/assets/scss/components/index.scss and add a new line pointing to your file:

@import '~comp/filter-bar/filter-bar.scss';

Note, ~comp is a shorthand to the src/_includes/components directory.

filter-bar.config.js

This file drives the component rendering for Project Franklin. It takes cues from Fractal and Storybook, and is effectively a big object that tells Project Franklin how to render the component, and what data to render it with. Let's run through the minimum viable config file:

module.exports = {
title: 'Filter bar',
component: {
name: 'filter-bar',
},
context: {
title: 'Filter bar title'
}
}

There are three mandatory sections:

  1. title: the name of component
  2. component: the same object we passed into the c() component, controling name, folder, and root
  3. context: the data used to render the component

If this is all correct, you should see 'Filter bar' in the components section of the Project Franklin sidebar.

Additional parameters

  • preview: Which 'preview' file should the component use to render. These live in src/_includes/components/component and allow you to test a component in a grid, with a different colour background, or in a totally different setting. To render your component with a new preview:
    • Create the preview-[PREVIEW NAME].njk file
    • Add any wrapping markup
    • Insert: {{ comp | safe }} wherever you wish to output the component
    • Add preview: '[PREVIEW NAME]' to your original component
  • docs: Does this component have a documentation markdown file (more on this later)?
  • figma: A link to the originally designed component within Figma
  • status: A string representation of how 'complete' the component is. This is 'slugified' and can be styled according to the name
  • version: A numeric value that can be increased every time you change the component
  • category: Components can be grouped in the Project Franklin sidebar. Categories are stored globally. To reference a category:
    1. Require the categories file in filter-bar.config.js:
    const categories = require('../component/categories');
    1. If you need a new category, create a new key/value pair in the above file
    2. Add the category parameter: category: categories.card
  • props: an array of prop tables, allowing you to document the inputs and outputs of the component:
{
props: [
{
title: 'Table title', // optional, defaults to 'Props'
table: [
['Parameter name', 'Parameter type', 'Parameter description']
]
}
]
}
  • variants: Variants are used to render the same component with different data, allowing you to test the parameters thoroughly, as well as test for extreme amounts of content and edge-cases. In Project Franklin, the variant objects are written like components within components. You must pass in a new title and a context object. Project Franklin will then merge the original component data with this new variant object to create a rendering context. This means you only have to pass the differences between the components, not every piece of context. It also means you can supply a different preview element, allowing you to test the same component in different scenarios.
{
variants: [
{
title: 'With long title',
context: {
title: 'Cras mattis consectetur purus sit amet fermentum. Etiam porta sem malesuada magna mollis euismod.'
}
},
{
title: 'In a grid',
preview: 'cards-three',
context: {}
}
]
}

filter-bar.md

Finally, you can create a Markdown file for a component. This is a space for you to write about the component in whatever way you deem helpful. This could be research insights, documentation of internal decisions, a changelog - it's up to you. This renders using the prose() component, so any styling from Project Franklin will be included here.