All components
A collection of every component and their variants as a cumulutive reference.Button
{{ design.patterns.renderPattern('button', {}) | safe }}
Source (Nunjucks)
{% if data.href %}
<a class="button" href="{{ data.href }}" {% if data.variant %}data-button-variant="{{ data.variant }}"{% endif %}>
{% else %}
<button class="button" {% if data.variant %}data-button-variant="{{ data.variant }}"{% endif %}>
{% endif %}
<span>{{ data.label }}</span>
{% include "icons/arrow.svg" %}
<span class="corner" aria-hidden="true"></span>
{% if data.href %}
</a>
{% else %}
</button>
{% endif %}
Variants
Link
{{ design.patterns.renderPattern('button/link', {}) | safe }}
Source (Nunjucks)
{% if data.href %}
<a class="button" href="{{ data.href }}" {% if data.variant %}data-button-variant="{{ data.variant }}"{% endif %}>
{% else %}
<button class="button" {% if data.variant %}data-button-variant="{{ data.variant }}"{% endif %}>
{% endif %}
<span>{{ data.label }}</span>
{% include "icons/arrow.svg" %}
<span class="corner" aria-hidden="true"></span>
{% if data.href %}
</a>
{% else %}
</button>
{% endif %}
Secondary
{{ design.patterns.renderPattern('button/secondary', {}) | safe }}
Source (Nunjucks)
{% if data.href %}
<a class="button" href="{{ data.href }}" {% if data.variant %}data-button-variant="{{ data.variant }}"{% endif %}>
{% else %}
<button class="button" {% if data.variant %}data-button-variant="{{ data.variant }}"{% endif %}>
{% endif %}
<span>{{ data.label }}</span>
{% include "icons/arrow.svg" %}
<span class="corner" aria-hidden="true"></span>
{% if data.href %}
</a>
{% else %}
</button>
{% endif %}
Card
{{ design.patterns.renderPattern('card', {}) | safe }}
Source (Nunjucks)
<article class="card">
<a href="{{ data.href }}">
<picture class="hover-anim"
data-static="{{ data.img.src }}.webp"
data-anim="{{ data.img.src }}-anim.webp">
<source type="image/webp" srcset="{{ data.img.src }}.webp">
<img
src="{{ data.img.src }}.webp"
alt="{{ data.img.alt }}"
loading="lazy"
draggable="false"/>
</picture>
{# The animation on hover effect for the card image #}
<script>
document.addEventListener('DOMContentLoaded', () => {
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
document.querySelectorAll('picture.hover-anim').forEach(pic => {
const img = pic.querySelector('img');
const source = pic.querySelector('source[type="image/webp"]');
if (!img) return;
const staticSrc = pic.dataset.static || img.currentSrc || img.src;
const animSrc =
pic.dataset.anim ||
staticSrc.replace(/(\.webp)(\?.*)?$/i, '-anim.webp$2'); // auto-derive
// If derived anim equals static, bail early
if (!animSrc || animSrc === staticSrc || reduceMotion) return;
// Preflight: only enable hover if the animation actually exists
const tester = new Image();
tester.onload = () => {
const swap = (url) => {
if (source) source.srcset = url; // drive <picture>
img.removeAttribute('srcset'); // ensure <picture> wins if any srcset lands
img.src = url; // mirror for fallback
};
// start/stop on hover (pointerenter/leave works for mouse + pen)
pic.addEventListener('pointerenter', () => swap(animSrc));
pic.addEventListener('pointerleave', () => swap(staticSrc));
// also reset on keyboard/tab focus changes just in case
pic.addEventListener('focusout', () => swap(staticSrc));
};
tester.onerror = () => {
// No anim available → do nothing, leave static image
// (You could console.debug here if you want)
};
tester.src = animSrc; // kicks off preflight
});
});
</script>
</a>
<div class="card__content flow">
<p class="card__runner">{{ data.runner }}</p>
<h2 class="card__title">{{ data.title }}</h2>
<p class="card__meta">{{ data.meta }}</p>
<p class="card__body">{{ data.description }}</p>
{% if data.alertText %}
<p class="card__alert">
<span>{{ data.alertText }}</span>
</p>
{% endif %}
<a class="button" href="{{ data.href }}">
<span>{{ data.buttonLabel }}</span>
{% include "icons/arrow.svg" %}
<span class="corner" aria-hidden="true"></span>
</a>
</div>
</article>
Variants
With alert text
{{ design.patterns.renderPattern('card/With alert text', {}) | safe }}
Source (Nunjucks)
<article class="card">
<a href="{{ data.href }}">
<picture class="hover-anim"
data-static="{{ data.img.src }}.webp"
data-anim="{{ data.img.src }}-anim.webp">
<source type="image/webp" srcset="{{ data.img.src }}.webp">
<img
src="{{ data.img.src }}.webp"
alt="{{ data.img.alt }}"
loading="lazy"
draggable="false"/>
</picture>
{# The animation on hover effect for the card image #}
<script>
document.addEventListener('DOMContentLoaded', () => {
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
document.querySelectorAll('picture.hover-anim').forEach(pic => {
const img = pic.querySelector('img');
const source = pic.querySelector('source[type="image/webp"]');
if (!img) return;
const staticSrc = pic.dataset.static || img.currentSrc || img.src;
const animSrc =
pic.dataset.anim ||
staticSrc.replace(/(\.webp)(\?.*)?$/i, '-anim.webp$2'); // auto-derive
// If derived anim equals static, bail early
if (!animSrc || animSrc === staticSrc || reduceMotion) return;
// Preflight: only enable hover if the animation actually exists
const tester = new Image();
tester.onload = () => {
const swap = (url) => {
if (source) source.srcset = url; // drive <picture>
img.removeAttribute('srcset'); // ensure <picture> wins if any srcset lands
img.src = url; // mirror for fallback
};
// start/stop on hover (pointerenter/leave works for mouse + pen)
pic.addEventListener('pointerenter', () => swap(animSrc));
pic.addEventListener('pointerleave', () => swap(staticSrc));
// also reset on keyboard/tab focus changes just in case
pic.addEventListener('focusout', () => swap(staticSrc));
};
tester.onerror = () => {
// No anim available → do nothing, leave static image
// (You could console.debug here if you want)
};
tester.src = animSrc; // kicks off preflight
});
});
</script>
</a>
<div class="card__content flow">
<p class="card__runner">{{ data.runner }}</p>
<h2 class="card__title">{{ data.title }}</h2>
<p class="card__meta">{{ data.meta }}</p>
<p class="card__body">{{ data.description }}</p>
{% if data.alertText %}
<p class="card__alert">
<span>{{ data.alertText }}</span>
</p>
{% endif %}
<a class="button" href="{{ data.href }}">
<span>{{ data.buttonLabel }}</span>
{% include "icons/arrow.svg" %}
<span class="corner" aria-hidden="true"></span>
</a>
</div>
</article>
Closer
{{ design.patterns.renderPattern('closer', {}) | safe }}
Source (Nunjucks)
<div class="closer">
<div class="wrapper flow">
{% include "icons/brand-exploded.svg" %}
{% if data.navItems.length %}
<nav aria-label="{{ data.navLabel }}" class="nav">
<ul class="cluster" role="list">
{% for item in data.navItems %}
<li>
<a href="{{ item.href }}" {% if item.current %}aria-current="page"{% endif %}>{{ item.label }}</a>
</li>
{% endfor %}
</ul>
</nav>
{% endif %}
</div>
</div>
Container fill text
{{ design.patterns.renderPattern('container-fill-text', {}) | safe }}
Source (Nunjucks)
<h2 class="container-fill-text">
<span class="container-fill-text__container">
<span class="container-fill-text__display">{{ data.text | safe }}</span>
</span>
<span class="container-fill-text__reference" aria-hidden="true">{{ data.text | safe }}</span>
</h2>
Information
This component is a progressively enhanced system. By default, the system will set a reasonably sensible large type size, but when JavaScript is enabled, the web component will kick in and calculate a perfect size based on the following argument:
multiplier: This should be modified by eye because different fonts render at different widths. This is mulitplied by 200 to calculate the container unit size.
Corner
{{ design.patterns.renderPattern('corner', {}) | safe }}
Source (Nunjucks)
<span class="corner" aria-hidden="true"></span>
Information
The corner block is a highly customisable presentation component. By default, it will be a 100px square with dark and light clips paths.
It can be configured as follows:
| Custom property | Default value |
|---|---|
--corner-size |
100px |
--corner-primary-color |
var(--color-light) |
--corner-secondary-color |
var(--color-dark) |
--corner-offset |
30% |
--corner-transition |
var(--transition-bounce) |
Variants
Themed with Custom Properties
{{ design.patterns.renderPattern('corner/themed', {}) | safe }}
Source (Nunjucks)
<style>
.my-element {
--corner-primary-color: var(--color-primary);
--corner-size: 50vh;
--corner-offset: 50%;
}
</style>
<div class="my-element">
<span class="corner" aria-hidden="true"></span>
</div>
{{ design.patterns.renderPattern('gallery', {}) | safe }}
Source (Nunjucks)
<section class="gallery">
<div class="wrapper flow">
<h2 class="section-title">{{ data.title }}</h2>
<p class="section-intro">{{ data.byline }}</p>
<p>{{ data.summary }}</p>
<div class="gallery grid">
{% for image in data.images %}
<div class="flow">
<picture>
<source srcset="{{ image.src }}.webp" type="image/webp">
<img src="{{ image.src }}.jpg" alt="{{ image.alt }}" loading="lazy"/>
</picture>
</div>
{% endfor %}
</div>
<div class="flow">
<a href="{{ data.button.href }}" class="button">
{{ data.button.label }}
</a>
</div>
</div>
</section>
Headline
{{ design.patterns.renderPattern('headline', {}) | safe }}
Source (Nunjucks)
<header class="headline repel">
<h2 class="headline__heading">{{ data.heading }}</h2>
<p class="labelled-icon {{ data.labelledIcon.utilities }}">
{{ data.labelledIcon.text }}
{% include "icons/arrow-down.svg" %}
</p>
</header>
Hero
{{ design.patterns.renderPattern('hero', {}) | safe }}
Source (Nunjucks)
<div class="hero">
<picture>
<source srcset="{{ data.img.src }}.webp" type="image/webp">
<img src="{{ data.img.src }}.jpg" alt="{{ data.img.alt }}" draggable="false"/>
</picture>
{# <img src="{{ data.img.src }}" alt="{{ data.img.alt }}" draggable="false"/> #}
<a href="{{ data.href }}" class="hero__skip-link flow">
<span class="hero__skip-link-icon">{% include "icons/arrow-down.svg" %}</span>
<h2><span class="hero__skip-link-label">{{ data.label }}</span></h2>
</a>
</div>
Hero - Smart layout / CSS Day 2025
{{ design.patterns.renderPattern('hero-smart', {}) | safe }}
Source (Nunjucks)
<div class="smart-layout debug-label">
<div class="smart-layout-item">
<article class="smart-card" data-container="true" data-type="quote">
<img class="placeholder" alt="Quote image"/>
<hgroup>
<h2 class="text-step-1">First item in HTML (Quotes 1)</h2>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit.</p>
</hgroup>
</article>
<article class="smart-card" data-container="true" data-type="quote">
<img class="placeholder" alt="Quote image"/>
<hgroup>
<h2 class="text-step-1">First item in HTML (Quotes 2)</h2>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit.</p>
</hgroup>
</article>
<article class="smart-card" data-container="true" data-type="quote">
<img class="placeholder" alt="Quote image"/>
<hgroup>
<h2 class="text-step-1">First item in HTML (Quotes 3)</h2>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit.</p>
</hgroup>
</article>
<article class="smart-card" data-container="true" data-type="quote">
<img class="placeholder" alt="Quote image"/>
<hgroup>
<h2 class="text-step-1">First item in HTML (Quotes 4)</h2>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit.</p>
</hgroup>
</article>
</div>
<div class="smart-layout-item">
<article class="smart-card" data-container="true" data-type="featured">
<img class="placeholder" alt="Featured image"/>
<hgroup>
<h2 class="text-step-1">Second item in HTML (Featured)</h2>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Veritatis, impedit, officia, cumque
porro fugiat at quis nemo cum adipisci est dignissimos? Necessitatibus sed hic reiciendis magni est tempore repudiandae
quod.</p>
<button class="bevel">Find out more</button>
</hgroup>
</article>
</div>
<div class="smart-layout-item">
<article class="smart-card" data-container="true" data-type="misc">
<img class="placeholder" alt="Misc image"/>
<hgroup>
<h2 class="text-step-1">Third item in HTML (Misc)</h2>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Veritatis, impedit, officia, cumque
porro fugiat at quis nemo cum adipisci est dignissimos? Necessitatibus sed hic reiciendis magni est tempore repudiandae
quod.</p>
</hgroup>
</article>
</div>
</div>
Hero - Time Version
{{ design.patterns.renderPattern('hero-time', {}) | safe }}
Source (Nunjucks)
<div class="layout debug-label">
<article class="quoteWrapper">
<div class="cardWrapper quote" data-container="true">
<article class="cardArticle">
<div class="cardThumb"></div>
<hgroup class="cardContent">
<blockquote cite="https://www.huxley.net/bnw/four.html">
<h3 class="cardTitle">
Enthusiasm is free, so use it
</h3>
</blockquote>
<p>
<cite class="cardSubtitle">Arthur Turner, Manager of Headington / Oxford United, early-1960s</cite>
</p>
</hgroup>
</article>
</div>
<div class="cardWrapper quote" data-container="true">
<article class="cardArticle">
<div class="cardThumb"></div>
<hgroup class="cardContent">
<h3 class="cardTitle">Way too many people stopped growing in high school, constantly telling you about some mediocre
shit they did 40 years ago.</h3>
<p class="cardSubtitle">Unknown</p>
<p class="meta"></p>
</hgroup>
</article>
</div>
<div class="cardWrapper quote" data-container="true">
<article class="cardArticle">
<div class="cardThumb"></div>
<hgroup class="cardContent">
<blockquote cite="https://www.huxley.net/bnw/four.html">
<h3 class="cardTitle">
Websites are fun, the internet is a gift
</h3>
</blockquote>
<p>
<cite class="cardSubtitle">Henry who codes</cite>
</p>
</hgroup>
</article>
</div>
<div class="cardWrapper quote" data-container="true">
<article class="cardArticle">
<div class="cardThumb"></div>
<hgroup class="cardContent">
<blockquote cite="https://www.huxley.net/bnw/four.html">
<h3 class="cardTitle">
Websites are fun, the internet is a gift
</h3>
</blockquote>
<p>
<cite class="cardSubtitle">Henry who codes</cite>
</p>
</hgroup>
</article>
</div>
</article>
<article class="featureWrapper">
<div class="cardWrapper feature" data-container="true">
<article class="cardArticle">
<h2 class="cardThumb"></h2>
<hgroup class="cardContent">
<h3 class="cardTitle">Late-Night Screen Time Tied to Sleep</h3>
<p class="cardSubtitle">A new study finds that late-night screen time is linked to sleep problems.</p>
<p class="meta">By John Smith</p>
</hgroup>
</article>
</div>
</article>
<article class="recentWrapper">
<div class="cardWrapper recent" data-container="true">
<article class="cardArticle">
<div class="cardThumb"></div>
<hgroup class="cardContent">
<h3 class="cardTitle">Health Officials Urge Caution as Heat Builds</h3>
<p class="cardSubtitle"></p>
<p class="meta">By John Smith</p>
</hgroup>
</article>
</div>
</article>
</div>
Inspo
{{ design.patterns.renderPattern('inspo', {}) | safe }}
Source (Nunjucks)
<div class="inspo region indent">
<div class="corner" data-corner-docked data-corner-theme="primary"></div>
<div class="wrapper">
<h2 class="visually-hidden">{{ data.heading }}</h2>
<div class="inspo__grid">
{% for line in data.displayHeading %}
<p class="inspo__heading" aria-hidden="true">{{ line }}</p>
{% endfor %}
<div class="inspo__img">
<picture>
<source srcset="{{ data.img.src }}.webp" type="image/webp">
<img src="{{ data.img.src }}.jpg" alt="{{ data.img.alt }}" loading="lazy" draggable="false"/>
</picture>
{# <img src="{{ data.img.src }}" alt="{{ data.img.alt }}" loading="lazy"/> #}
</div>
</div>
</div>
<div class="inspo__stripe indent"></div>
</div>
Information
Some really important factors about this pattern are the following:
- The heading is visually hidden
- This heading should be broken on to two lines, which are in turn, distributed by CSS grid
- Try to keep the heading short and snappy
- Make sure the image fits nicely in a 16/9 aspect ratio
Labelled Icon
{{ design.patterns.renderPattern('labelled-icon', {}) | safe }}
Source (Nunjucks)
<p class="labelled-icon {{ data.utilities }}">
{{ data.text }}
{% include "icons/arrow-down.svg" %}
</p>
Information
This block is mainly structural because the visuals will be controlled by a wider page context. Therefore, colour is inherited by default.
It's recommended to use utilities for specific styling, just like this variant.
<p class="labelled-icon text-light text-step-2">…</p>
Variants
Styled with utilities
{{ design.patterns.renderPattern('labelled-icon/Styled with utilities', {}) | safe }}
Source (Nunjucks)
<p class="labelled-icon {{ data.utilities }}">
{{ data.text }}
{% include "icons/arrow-down.svg" %}
</p>
Masthead
{{ design.patterns.renderPattern('masthead', {}) | safe }}
Source (Nunjucks)
<div class="masthead">
<h1 class="masthead__heading">{{ data.heading }}</h1>
<p class="masthead__location">{{ data.location }}</p>
<p class="masthead__meta">{{ data.meta }}</p>
<div class="masthead__logo-left" aria-hidden="true">
{% include "icons/brand-left.svg" %}
</div>
<div class="masthead__logo-right" aria-hidden="true">
{% include "icons/brand-right.svg" %}
</div>
</div>
Nav
{{ design.patterns.renderPattern('nav', {}) | safe }}
Source (Nunjucks)
<nav aria-label="{{ data.label }}" class="nav">
<ul class="{{ 'flow' if data.variant === 'stacked' else 'cluster' }}" role="list">
{% for item in data.items %}
<li>
<a href="{{ item.href }}" {% if item.current %}aria-current="page"{% endif %}>{{ item.label }}</a>
</li>
{% endfor %}
</ul>
</nav>
Information
The layout is controlled by flow and cluster. The variants in this pattern library only change that layout system.
By design, the nav will inherit font size, so it's imperative you account for that in your page context, either with utility classes or context specific CSS.
Variants
Stacked
{{ design.patterns.renderPattern('nav/stacked', {}) | safe }}
Source (Nunjucks)
<nav aria-label="{{ data.label }}" class="nav">
<ul class="{{ 'flow' if data.variant === 'stacked' else 'cluster' }}" role="list">
{% for item in data.items %}
<li>
<a href="{{ item.href }}" {% if item.current %}aria-current="page"{% endif %}>{{ item.label }}</a>
</li>
{% endfor %}
</ul>
</nav>
Global CSS & Prose
{{ design.patterns.renderPattern('prose', {}) | safe }}
Source (Nunjucks)
<article class="wrapper prose flow">
<h1>Prose content and global styles kitchen sink</h1>
<p>We start with a paragraph of text that features various HTML tags, used in flow content. Account for <em>emphasis</em>, <strong>strong</strong> and <small>small</small> text. Don’t forget to account for abbreviations too, using the <abbr title="abbreviation">abbr</abbr> (<code><abbr></code>) element. Lastly you can define <del>deleted text</del>
<ins>inserted text</ins>.</p>
<p>If you are referencing keyboard keys, make sure you use the <code><kbd></code> element like this: <kbd>shift</kbd>. Like we have already in these paragraphs, if you are referencing code, use the <code><code></code> element. Don’t forget the <code><samp></code> element either. An example for that element is this: <samp>Press F1 to continue</samp>. </p>
<p>Use the <code><var></code> element to reference a variable like this: The volume of a box is <var>l</var> × <var>w</var> × <var>h</var>, where <var>l</var> represents the length, <var>w</var> the width and <var>h</var> the height of the box.</p>
<p>If you want an inline quote, use the <code><q></code> element <q>quoted text</q>. Lastly don’t forget the subscript (<code><sub></code>) (H<sub>2</sub>O) and superscript (<code><sup></code>) (E = MC<sup>2</sup>), and of course, <a href="https://example.com">link elements</a>. </p>
<h2>Blockquote styles are the context for this heading level 2 which is long for testing leading and balance</h2>
<blockquote>
<p>Sed posuere consectetur est at lobortis. Nullam id dolor id nibh ultricies vehicula ut id elit. Cras mattis consectetur purus sit amet fermentum.</p>
</blockquote>
<blockquote cite="https://www.huxley.net/bnw/four.html">
<q>Words can be like X-rays, if you use them properly—they’ll go through anything. You read and you’re pierced.</q>
<footer>Aldous Huxley, <cite>Brave New World</cite>
</footer>
</blockquote>
<p>Make sure you only use a cite if the quote source can be linked to.</p>
<hr>
<p>Just a quick paragraph to follow the horizontal rule. A bit of Lipsum? Sure thing: Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.</p>
<h2>Details and summary</h2>
<details>
<summary>Toggle the details element</summary>
<p>Previously hidden content until the details element is in its <code>open</code> state.
</details>
<h2>Tables</h2>
<table>
<caption>A nice caption for this table</caption>
<tbody>
<tr>
<th>Person</th>
<th>Number</th>
<th>Third Column</th>
</tr>
<tr>
<td>Someone Lastname</td>
<td>900</td>
<td>Nullam quis risus eget urna mollis ornare vel eu leo.</td>
</tr>
<tr>
<td>
<a href="#">Person Name</a>
</td>
<td>1200</td>
<td>Vestibulum id ligula porta felis euismod semper. Donec ullamcorper nulla non metus auctor fringilla.</td>
</tr>
<tr>
<td>Another Person</td>
<td>1500</td>
<td>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nullam id dolor id nibh ultricies vehicula ut id elit.</td>
</tr>
<tr>
<td>Last One</td>
<td>2800</td>
<td>Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cras mattis consectetur purus sit amet fermentum.</td>
</tr>
</tbody>
</table>
<p>Sometimes, a table has column headers</p>
<table>
<caption>A nice caption for this table</caption>
<tbody>
<tr>
<th></th>
<th>Person</th>
<th>Number</th>
<th>Third Column</th>
</tr>
<tr>
<th>This column’s heading</th>
<td>Someone Lastname</td>
<td>900</td>
<td>Nullam quis risus eget urna mollis ornare vel eu leo.</td>
</tr>
<tr>
<th>Another column heading</th>
<td>
<a href="#">Person Name</a>
</td>
<td>1200</td>
<td>Vestibulum id ligula porta felis euismod semper. Donec ullamcorper nulla non metus auctor fringilla.</td>
</tr>
<tr>
<th>Code in tables should have more paired back styles</th>
<td>Another Person</td>
<td>
<code>1500</code>
</td>
<td>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nullam id dolor id nibh ultricies vehicula ut id elit.</td>
</tr>
<tr>
<th>Last column header</th>
<td>Last One</td>
<td>2800</td>
<td>Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cras mattis consectetur purus sit amet fermentum.</td>
</tr>
</tbody>
</table>
<h2>Description lists time</h2>
<p>Just a quick paragraph to introduce heading level 3 too.</p>
<h3>Description lists are under-used, but extremely useful</h3>
<dl>
<dt>A description list term</dt>
<dd>A description list detail</dd>
<dt>Another term</dt>
<dd>A slightly longer details element to work with.</dd>
</dl>
<h3>Sometimes description lists have multiple details</h3>
<dl>
<dt>This term introduces two details</dt>
<dd>This is the first one</dd>
<dd>This is the second one, which is a bit longer</dd>
</dl>
<h2>Lists, glorious lists</h2>
<p>Lists in various forms.</p>
<h3>A simple undordered list</h3>
<ul>
<li>List item one</li>
<li>List item two</li>
<li>List item three, which is a longer item to make sure our marker styles work well for mult-line list items</li>
<li>List item four</li>
</ul>
<h3>Moving on to a nested undordered list</h3>
<ul>
<li>Unordered List item one <ul>
<li>Nested list item <ul>
<li>Level 3, item one</li>
<li>Level 3, item two</li>
<li>Level 3, item three</li>
<li>Level 3, item four</li>
</ul>
</li>
<li>List item two</li>
<li>List item three</li>
<li>List item four</li>
</ul>
</li>
<li>List item two</li>
<li>List item three</li>
<li>List item four</li>
</ul>
<h3>Order, numbered lists are next</h3>
<ol>
<li>List item one</li>
<li>List item two</li>
<li>List item three, which is a longer item to make sure our marker styles work well for mult-line list items</li>
<li>List item four</li>
</ol>
<h3>Moving on to a nested undordered list</h3>
<ol>
<li>Ordered List item one <ol>
<li>Nested list item <ol>
<li>Level 3, item one</li>
<li>Level 3, item two</li>
<li>Level 3, item three</li>
<li>Level 3, item four</li>
</ol>
</li>
<li>List item two</li>
<li>List item three</li>
<li>List item four</li>
</ol>
</li>
<li>List item two</li>
<li>List item three</li>
<li>List item four</li>
</ol>
<h3>A mix of both</h3>
<ul>
<li>Unordered List item one <ol>
<li>Nested ordered list item <ul>
<li>Level 3, item one</li>
<li>Level 3, item two</li>
<li>Level 3, item three</li>
<li>Level 3, item four</li>
</ul>
</li>
<li>List item two</li>
<li>List item three</li>
<li>List item four</li>
</ol>
</li>
<li>List item two</li>
<li>List item three</li>
<li>List item four</li>
</ul>
<h2>Preformatted text / blocks of code styles follow on next</h2>
<pre><code>.context-alert {
position: absolute;
inset: auto 0 calc(100% + 0.5em) 0;
padding: 0.25em;
background: var(--color-primary);
color: var(--color-light);
font-weight: var(--font-bold);
text-align: center;
transition: opacity var(--transition-fade) 200ms,
transform var(--transition-bounce-fast) 200ms;
}</code></pre>
<h2>Forms</h2>
<form>
<div>
<label for="input-email">Email address with placeholder</label>
<input type="email" id="input-email" placeholder="E.G name@domain.com">
</div>
<div>
<label for="input-number">Number</label>
<input type="number" id="input-number">
</div>
<div>
<label for="input-password">Password</label>
<input type="password" id="input-password">
</div>
<div>
<label for="input-search">Search</label>
<input type="search" id="input-search">
</div>
<div>
<label for="input-tel">Telephone number</label>
<input type="tel" id="input-tel">
</div>
<div>
<label for="input-text">Text</label>
<input type="text" id="input-text">
</div>
<div>
<label for="input-url">Url with placeholder</label>
<input type="url" id="input-url" placeholder="https://example.com">
</div>
<div>
<label for="input-color">Color</label>
<input type="color" id="input-color" value="#ff00ff">
</div>
<div>
<label for="input-date">Date</label>
<input type="date" id="input-date">
</div>
<div>
<label for="input-date-time-local">Date and time</label>
<input type="datetime-local" id="input-date-time-local">
</div>
<div>
<label for="input-month">Month</label>
<input type="month" id="input-month">
</div>
<div>
<label for="input-week">Week</label>
<input type="week" id="input-week">
</div>
<div>
<label for="input-time">Time</label>
<input type="time" id="input-time">
</div>
<div>
<label for="input-select">Example select</label>
<select id="input-select">
<option>Option number 1</option>
<option>Option number 2</option>
<option>Option number 3</option>
<option>Option number 4</option>
<option>Option number 5</option>
</select>
</div>
<div>
<label for="input-multi-select">Example multiple select</label>
<select multiple id="input-multi-select">
<option>Option number 1</option>
<option>Option number 2</option>
<option>Option number 3</option>
<option>Option number 4</option>
<option>Option number 5</option>
</select>
</div>
<div>
<label for="input-datalist">Example datalist</label>
<input list="datalist-list-element" id="input-datalist">
<datalist id="datalist-list-element">
<option>Option number 1</option>
<option>Option number 2</option>
<option>Option number 3</option>
<option>Option number 4</option>
<option>Option number 5</option>
</datalist>
</div>
<div>
<label for="input-textarea">Example textarea</label>
<textarea id="input-textarea" rows="3"></textarea>
</div>
<div>
<label for="input-textarea-no-rows">Example textarea with no rows attribute</label>
<textarea id="input-textarea-no-rows"></textarea>
</div>
<div>
<label for="input-file">File input</label>
<input type="file" id="input-file">
</div>
<div>
<label for="input-disabled">A disabled input</label>
<input type="text" id="input-disabled" disabled>
</div>
<div>
<label for="input-readonly">A readonly input</label>
<input type="text" id="input-readonly" readonly value="Some readonly text">
</div>
<fieldset>
<legend>I am a legend element for radio inputs</legend>
<label>
<input type="radio" name="input-radios" id="radio-1" value="option-1" checked>
<span>We put the label text in a span because we can use <code>:has()</code> to style radios and checkboxes with flexbox</span>
</label>
<label>
<input type="radio" name="input-radios" id="radio-2" value="option-2">
<span>
The second option should de-select option 1
</span>
</label>
<label>
<input type="radio" name="input-radios" id="radio-3" value="option3" disabled>
<span>This one is disabled and can’t be selected</span>
</label>
</fieldset>
<fieldset>
<legend>I am also a legend but this time for checkboxes</legend>
<label>
<input type="checkbox" id="input-checkbox">
<span>Checkbox number one</span>
</label>
<label>
<input type="checkbox" id="input-checkbox-1">
<span>Checkbox number two has a longer label to make sure our CSS is top notch</span>
</label>
<label>
<input type="checkbox" id="input-checkbox-2" disabled>
<span>Checkbox number three is disabled and cant’t be checked</span>
</label>
</fieldset>
</form>
<p>Where are buttons? Good question. Not here because we don’t tend to style up default buttons and instead opt to treat them as components with a <code>.button</code> class.</p>
<h2>Images, figures, pictures and videos</h2>
<p>Under no circumstances should you have an image without an <code>alt</code> attribute. At a minimum, it should be an empty value like this one. That should only be used for purely decorative images though. </p>
<img eleventy:ignore src="https://images.unsplash.com/photo-1579546929518-9e396f3cc809?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8fHx8fHx8MTY4MjA3NzQ4Mg&ixlib=rb-4.0.3&q=80&w=1080" alt="">
<h3>An image in a figure with a caption</h3>
<figure>
<img eleventy:ignore src="https://images.unsplash.com/photo-1696251143046-2d32fb985b59?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=4470&q=80" alt="A Tokyo street in the early evening dusk. The shot is from under a steel bridge where there is a store, lit up, which in turn, lights up the surrounding area.">
<figcaption>Tokyo, Japan, looking stunning in the early evening. By <a href="https://unsplash.com/@ayumikubo">ayumi kubo</a>
</figcaption>
</figure>
<h3>A picture element</h3>
<picture eleventy:ignore>
<source srcset="https://images.unsplash.com/photo-1692946573219-2257a4a29cad?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1500&h=1500&q=80" media="(min-width: 1500px)">
<source srcset="https://images.unsplash.com/photo-1692946573219-2257a4a29cad?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=800&q=80" media="(orientation: portrait)">
<img eleventy:ignore src="https://images.unsplash.com/photo-1692946573219-2257a4a29cad?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=500&h=500&q=80" alt="An above shot of some very green leaves">
</picture>
<h3>A video element</h3>
<video controls src="https://assets.codepen.io/174183/flower.mp4"></video>
<h3>An SVG with an image role and alternative text</h3>
<svg role="img" aria-label="a black spiral" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 331.27 316.68" width="500" height="500">
<path fill="#000" d="M182.4,339.4a152.15,152.15,0,0,1-53.8-9.9A155.78,155.78,0,0,1,28.7,188.4,159.57,159.57,0,0,1,72.4,73.9,165,165,0,0,1,251,33.7a169,169,0,0,1,94,89,173,173,0,0,1,14.9,65.4l-10,.3A160.63,160.63,0,0,0,299.8,75.9a158.8,158.8,0,0,0-52.3-32.8,156.72,156.72,0,0,0-60.2-10.2A153.62,153.62,0,0,0,79.8,81a153,153,0,0,0-31.3,49.9,150.15,150.15,0,0,0-9.7,57.4,147.9,147.9,0,0,0,12.9,56.1,145.82,145.82,0,0,0,33,46.2,144,144,0,0,0,47.6,29.7,141.53,141.53,0,0,0,108-3.2,139.62,139.62,0,0,0,43.9-31.4,138.19,138.19,0,0,0,28.2-45.2,135.22,135.22,0,0,0,8.6-51.9v-.3a133.79,133.79,0,0,0-11.8-50.4,130.65,130.65,0,0,0-72.8-68.1A127,127,0,0,0,139.5,73a124.84,124.84,0,0,0-39.2,28.3,122.5,122.5,0,0,0-25,40.5,119,119,0,0,0,3.2,91.3A117.52,117.52,0,0,0,105.2,270a116.09,116.09,0,0,0,38.2,23.5,112.41,112.41,0,0,0,85.8-3.2,109.78,109.78,0,0,0,34.5-25.1,108.34,108.34,0,0,0,21.9-35.8,104.88,104.88,0,0,0,6.4-40.8v-.2a102.95,102.95,0,0,0-33.2-71.5A98.37,98.37,0,0,0,150.6,99.8a96.58,96.58,0,0,0-29.8,22A94.57,94.57,0,0,0,102,152.9a90.45,90.45,0,0,0,3.1,69.1,88.84,88.84,0,0,0,20.4,27.5,86.82,86.82,0,0,0,28.7,17.2,83.27,83.27,0,0,0,63.6-3.2,78.84,78.84,0,0,0,25.1-18.8,79.77,79.77,0,0,0,15.7-26.4,76.75,76.75,0,0,0,4.2-29.7v-.2a75.91,75.91,0,0,0-7.3-28.2,74.17,74.17,0,0,0-17.2-22.8,72,72,0,0,0-24-14.1,68.73,68.73,0,0,0-52.5,3.2,65.22,65.22,0,0,0-20.4,15.7,63.75,63.75,0,0,0-12.5,21.7,61.63,61.63,0,0,0-3.1,24.1,59.53,59.53,0,0,0,6.2,22.8,57.9,57.9,0,0,0,14.1,18.1,57.22,57.22,0,0,0,19.3,11,55.31,55.31,0,0,0,21.4,2.6,52,52,0,0,0,35.8-18.1,48.88,48.88,0,0,0,11.5-35.6v-.3a47.14,47.14,0,0,0-5-17,44.33,44.33,0,0,0-10.9-13.4,42.4,42.4,0,0,0-14.6-7.9,40,40,0,0,0-15.8-1.5,37.19,37.19,0,0,0-14.5,4.5,35.59,35.59,0,0,0-11.1,9.3,34.65,34.65,0,0,0-6.3,12.2,33.45,33.45,0,0,0-1,13,30,30,0,0,0,3.9,11.7,30.94,30.94,0,0,0,7.7,8.8,28,28,0,0,0,9.8,4.8,25.44,25.44,0,0,0,10.3.5,25,25,0,0,0,8.9-3.2,23.63,23.63,0,0,0,6.5-6.1,21.32,21.32,0,0,0,3.3-7.4,18.94,18.94,0,0,0,0-7.5l-.1-.3a15.54,15.54,0,0,0-6.9-10,12.22,12.22,0,0,0-4.9-1.8,11.47,11.47,0,0,0-4.8.4,7.35,7.35,0,0,0-3.2,1.8,10,10,0,0,0-2,2.6,4.41,4.41,0,0,0-.5,1.9h0l.5-1.7,4.3.8a4.51,4.51,0,0,1,1.1.3l2.7-.5.5,2.8a5.39,5.39,0,0,1,.7,1.3l-.2.9,1.2,4.6-.7.2.3,1.7-2.6-.5a12,12,0,0,1-1.1,1.2,8.24,8.24,0,0,1-5.8,1.8,10.78,10.78,0,0,1-4.9-1.5,11.85,11.85,0,0,1-4.3-4.6l-.1-.1a14.34,14.34,0,0,1-1.5-5.7,15.94,15.94,0,0,1,1.4-7,19.79,19.79,0,0,1,4.4-6A18.07,18.07,0,0,1,186,168a21.66,21.66,0,0,1,17.6,2.5,26.67,26.67,0,0,1,7.3,6.9,25.6,25.6,0,0,1,4.2,9.9l.1.6a28.53,28.53,0,0,1-.2,10.9,30.21,30.21,0,0,1-4.9,11.2A32.8,32.8,0,0,1,188,223.4a35.68,35.68,0,0,1-14.2-.7,39.22,39.22,0,0,1-13.5-6.5A39.76,39.76,0,0,1,144.9,189a43.47,43.47,0,0,1,1.3-16.9,46.53,46.53,0,0,1,8.1-15.8,47.29,47.29,0,0,1,32.3-17.4,50.39,50.39,0,0,1,19.7,1.9,53.84,53.84,0,0,1,18.1,9.7A55,55,0,0,1,237.8,167a56.72,56.72,0,0,1,6.2,21v.3a57.39,57.39,0,0,1-2.5,22.2,58.55,58.55,0,0,1-11.3,20.4,61.69,61.69,0,0,1-18.8,14.9,63.21,63.21,0,0,1-23.8,6.7,63.9,63.9,0,0,1-25.3-3.1,67.49,67.49,0,0,1-22.7-12.9,68.23,68.23,0,0,1-16.5-21.2,69.25,69.25,0,0,1-7.2-26.6,71.61,71.61,0,0,1,3.6-28,74.68,74.68,0,0,1,38.1-43.1,78.1,78.1,0,0,1,60.1-3.6,81.92,81.92,0,0,1,47,41.9A84.73,84.73,0,0,1,273,188v.3a86.3,86.3,0,0,1-4.8,33.4,89.32,89.32,0,0,1-46,50.9,92.64,92.64,0,0,1-34.9,8.8,95.3,95.3,0,0,1-36.3-5.3,96.56,96.56,0,0,1-54.8-49.8,99.29,99.29,0,0,1-9.4-37.7,101.84,101.84,0,0,1,26.7-73.5,105.45,105.45,0,0,1,33-24.3,108.28,108.28,0,0,1,40.5-10,110.73,110.73,0,0,1,41.9,6.4,111.16,111.16,0,0,1,62.7,57.6A114.76,114.76,0,0,1,302.1,188v.2a116,116,0,0,1-31,83.7,120,120,0,0,1-83.7,38.4,123.5,123.5,0,0,1-47.4-7.6,125.51,125.51,0,0,1-41.5-25.5,127.2,127.2,0,0,1-40.6-88.8,130.7,130.7,0,0,1,35.2-94,134.21,134.21,0,0,1,94-42.7,138.85,138.85,0,0,1,53,8.6,140.3,140.3,0,0,1,46.2,28.6,141.86,141.86,0,0,1,44.8,99v.3a145.36,145.36,0,0,1-39.4,104.2,148.88,148.88,0,0,1-104.2,46.9C185.6,339.4,184,339.4,182.4,339.4Z" transform="translate(-28.63 -22.72)"/>
</svg>
<h2>All of the headings</h2>
<p>We tend to only specifically style up headings up to level 4 in terms of leading and balance because if you’re getting into 5 and 6, you probably want to be simplifying your content. We’ll add them here though to double check they look OK.</p>
<h1>Sed posuere consectetur est at lobortis.</h1>
<h2>Sed posuere consectetur est at lobortis.</h2>
<h3>Sed posuere consectetur est at lobortis.</h3>
<h4>Sed posuere consectetur est at lobortis.</h4>
<h5>Sed posuere consectetur est at lobortis.</h5>
<h6>Sed posuere consectetur est at lobortis.</h6>
</article>
Quote
{{ design.patterns.renderPattern('quote', {}) | safe }}
Source (Nunjucks)
<blockquote {% if data.cite %}cite="{{ data.cite.url }}"{% endif %}>
{% if data.content %}
<p>{{ data.content }}</p>
{% endif %}
{% if data.quote %}
<q>{{ data.quote }}</q>
{% endif %}
{% if data.cite %}
<footer>
<cite>{{ data.cite.text }}</cite>
</footer>
{% endif %}
</blockquote>
Variants
With Cite
{{ design.patterns.renderPattern('quote/With Cite', {}) | safe }}
Source (Nunjucks)
<blockquote {% if data.cite %}cite="{{ data.cite.url }}"{% endif %}>
{% if data.content %}
<p>{{ data.content }}</p>
{% endif %}
{% if data.quote %}
<q>{{ data.quote }}</q>
{% endif %}
{% if data.cite %}
<footer>
<cite>{{ data.cite.text }}</cite>
</footer>
{% endif %}
</blockquote>
Rolodex
{{ design.patterns.renderPattern('rolodex', {}) | safe }}
Source (Nunjucks)
<div class="rolodex">
<ol class="rolodex__list flow" role="list">
{% for item in data.items %}
<li>
<a href="{{ item.link }}" class="rolodex__item sidebar" data-rolodex-theme="{{ item.theme }}" data-reversed>
<h3 class="rolodex__heading">
<span class="rolodex__number">*{{ item.heading.number }}</span>
<span>{{ item.heading.text }}</span>
</h3>
<picture>
<source srcset="{{ item.img.src }}.webp" type="image/webp">
<img src="{{ item.img.src }}.jpg" alt="{{ item.img.alt }}" loading="lazy" draggable="false"/>
</picture>
{# <img src="{{ item.img.src }}" alt="{{ item.img.alt }}"/> #}
</a>
</li>
{% endfor %}
</ol>
</div>
Information
Each Rolodex item can be themed with the following attribute values:
| Value | Description |
|---|---|
data-rolodex-theme="light" |
White background with dark text. This is the default. |
data-rolodex-theme="primary" |
Primary background with dark text. |
data-rolodex-theme="dark" |
Dark background with light text. |
You can also change the colour of the triangle mask by setting a value for --rolodex-triangle-color in a higher context. For example, if your section of the page has a var(--color-light) background, set --rolodex-triangle-color to var(--color-light) too.
Site Foot
{{ design.patterns.renderPattern('site-foot', {}) | safe }}
Source (Nunjucks)
<footer class="site-foot">
<div class="wrapper repel">
<p class="">© Gonk Design {% year %}</p>
<div class="madeInAustralia" >
<img src="/images/madeInAustralia.svg"/>
<p class="made">Made in</p>
{# <hr> #}
<p class="au">Australia</p>
</div>
<p class="">All rights reserved.</p>
</div>
</footer>
Site Head
{{ design.patterns.renderPattern('site-head', {}) | safe }}
Source (Nunjucks)
<header class="site-head wrapper">
<div class="repel site-head__inner">
<div class="site-head__brand">
<a href="/">
{{ data.brandName }}
</a>
</div>
<nav aria-label="primary" class="nav">
<ul class="cluster" role="list">
{% for item in data.items %}
<li>
<a href="{{ item.href }}" {% if item.current %}aria-current="page"{% endif %}>{{ item.label }}</a>
</li>
{% endfor %}
</ul>
</nav>
</div>
<hr/>
</header>