Building a component based style guide for Kirby (1)
Some time ago, Thomas published an article, in which he described how he creates an overview of UI components used in a project to test them in different constellations. He calls it Kirby Playground. It reminds me a lot of my custom style guide module, which I originally developed for Drupal a few years ago. But I use the same system for Kirby projects as well for quite a long time now. I would like to take this as an opportunity to explain my approach.
As the topic is very extensive, I am dividing it into several parts. Otherwise I would probably never finish the blog post. And Thomas insisted on this as we met at Beyond Tellerrand.
The goal
In the end we want to get an overview page of all the components (see below) used in the web project. This allows all components to be visually tested at a glance. It's a quick check if the frontend is working as expected and could be automated with Cypress or similar tools. This overview also makes it easier for several developers to work together, as well as to coordinate with the designers.
In addition we want a single page for every component, which can be used to add further instructions. Additional variants of the component, which would possibly overload the overview page, can be shown there as well. Optionally, the HTML source code or the implementation of the Kirby snippet can be displayed, which facilitates later integration into the CMS templates. We will cover this in the following parts of this series.
Frontend components
The basis of the entire system is the use of frontend components. By this I mean the various ways used to display content on a website. These are, for example, banners, teasers or boxes – but also smaller elements such as buttons or simple text elements.
To keep every component separated, there is a directory site/snippets/component/
in which all components are collected as Kirby snippets. If you follow the atomic design principle, you can of course define further subfolders. For my part, I get along well with a single directory.
These snippets provide the HTML structure. The aim is to ensure that this HTML does not have to be used anywhere else. This is not always feasible for all modules. Particularly with very small components such as buttons, I have found that a central snippet with all the variations often complicates matters. However, we can ignore this for the time being.
Example: A snippet for a teaser component would go into the site/snippets/component/teaser.php
file and could look like this:
<article class="teaser <?= $modifier ?? '' ?>">
<?php if (!empty($headline)): ?>
<h1 class="teaser__headline">
<?= $headline ?>
</h1>
<?php endif ?>
<?php if (!empty($image)): ?>
<div class="teaser__image">
<?= $image ?>
</div>
<?php endif ?>
<?php if (!empty($text)): ?>
<p class="teaser__text">
<?= $text ?>
</p>
<?php endif ?>
<?php if (!empty($url)): ?>
<a class="teaser__link" href="<?= $url ?>">
<?= t('teaser.more', 'More') ?>
</a>
<?php endif ?>
</article>
Each variable inside a component snippet is considered a string. This is important. There are no things like Kirby objects which makes it possible that we can easily pass simple static content to it. We come back again to this later. To avoid empty HTML elements we need a lot of if
statements. If you don’t care about empty HTML elements (you should!) or if you make sure that every teaser comes, e.g. with a headline you could use <?= $headline ?? '' ?>
instead and omit the if
statement around.
The structure of HTML and CSS is totally up to you, of course. In this example we use the BEM system which separates the component styles strictly from each other. Every component has a matching SCSS/SASS file with the same name, e.g. /src/styles/component/teaser.scss
. This makes it very easy to find the related file in your editor.
Component snippets in action
Now the components are ready to be used like every other Kirby snippet.
// assuming $article is a page object
snippet('component/teaser', [
'modifier' => 'teaser--featured',
'headline' => $article->title()->esc(),
'image' => $article->image(),
'text' => $article->content()->intro()->kti(),
'url' => $article->url(),
]);
One more (optional) layer …
You could stop here. But if this code is used in several places, I like to create another snippet. This might be confusing at first, but we need to separate the frontend component snippets (which will later also be used in the style guide) from the Kirby snippets which are tied to the page type.
One way could be to create a custom snippets folder and name the snippets based on the page type (article) and the component (teaser). In the end there would be a folder structure like this one:
site/snippets/custom/article-teaser.php
site/snippets/custom/article-card.php
site/snippets/custom/news-teaser.php
site/snippets/custom/news-card.php
Or if you prefer subfolders, the following structure might fit your needs a bit better.
site/snippets/teaser/article.php
site/snippets/teaser/news.php
site/snippets/card/article.php
site/snippets/card/news.php
Based on the last structure the article teaser would be used somewhere in your Kirby templates like this and could then easily be re-used elsewhere.
if ($article = $kirby->collection('articles')->first()) {
snippet('teaser/article', ['article' => $article]);
}
Whats next?
In the next part I want to show you, how to set up the routes to get an overview page as well as a detailed page for every component.
Sources
- Kirby Playground (Thomas Günther)
- Kirby Snippets (Kirby Website)
- Atomic Design (Brad Frost)
- CSS BEM
Change Log
- 12.05.2025 – Added examples how to use frontend component snippets in Kirby templates
- 30.05.2025 – Added link to the follow-up blog post
CMS Kirby PHP #Style guide #Components
What do you think?
Let's discuss on Mastodon