2012
The agency starts
A compact development team that builds software meant to last.
All components are controlled through JSX comments above the markdown element. The general syntax is:
{/* prop="waarde" andere-prop="waarde" */}
(markdown element below)Section components (Hero, SideBySide, Showcase, FeatureSection, FeatureListSection, TechnologySection, KeyTakeaways, TestimonialCarousel, CaseStudyCarousel, CaseOverview, FAQ, Timeline) are closed with a horizontal rule (---).
The Hero is the first block on a page. It supports a background image, a title, a bullet list, and action buttons.
A page with layout: page and this hero block needs a pageKind in its frontmatter. This determines the height, alignment, decoration, and permitted number of bullets and buttons. Do not set individual height, grid, hexagons, or align attributes on the hero directive.
pageKind | Use | Bullets | Buttons |
|---|---|---|---|
section-overview | Section overview | up to 4 | up to 2 |
cluster-overview | Cluster overview | none | up to 1 |
service-detail, method-detail, technology-detail, longtail-landing | Detail page or targeted landing page | up to 3 | up to 1 |
utility | Practical page or documentation | none | up to 1 |
The optional overline text can still be set on the hero directive. Cases and blog articles get their hero automatically from their layout. Contact and Our team use their own opening blocks.
On a comment before a link paragraph:
| Prop | Values |
|---|---|
color | primary, secondary, gray |
icon | arrow-right |
---
layout: page
pageKind: utility
title: Example page
description: An example of a practical page with a compact hero.
---
{/* hero */}

# Example _hero_
A short introduction with one next step.
{/* color="secondary" icon="arrow-right" */}
[View cases](/en/cases)
---Displays an image next to text. Image position is determined automatically: if the image is above the text, it appears on the left; if it is below the text, it appears on the right.
| Prop | Values | Default |
|---|---|---|
background | white, light-grey, dark-secondary, dark-primary, dark-gray | white |
shapes | comma-separated: hexagon, dots, rhombus, arrow, polygons | — |
 — Image```mermaid diagram or a code block (see below)#### — Overline## — Title (supports *emphasis*)- list — Bullet list (optional, supports **bold** labels)[text](url) — Action link (with optional {/* icon="arrow-right" */})The media slot accepts an image, a mermaid diagram, or a code block. For a diagram or code block, the same position logic applies (above the text = left, below = right), and you can set the background with a comment above it, just as with a standalone Code Block or Mermaid diagram.
{/* side-by-side shapes="hexagon,dots,rhombus,arrow" */}

#### EXAMPLE • DOCUMENTATION
## Image _left_
The image sits above the text in the MDX, so it is shown on the left. This is the default behaviour. Leave a blank line between text and image.
{/* icon="arrow-right" */}
[More information](/en/docs)
---EXAMPLE • DOCUMENTATION
The image sits above the text in the MDX, so it is shown on the left. This is the default behaviour. Leave a blank line between text and image.
More information{/* side-by-side background="light-grey" shapes="polygons" */}
#### EXAMPLE • DOCUMENTATION
## Image _right_
The image sits below the text in the MDX, so it is shown on the right. The background is light-grey with polygons shapes. Leave a blank line between text and image.

{/* icon="arrow-right" */}
[More information](/en/docs)
---EXAMPLE • DOCUMENTATION
The image sits below the text in the MDX, so it is shown on the right. The background is light-grey with polygons shapes. Leave a blank line between text and image.
More information{/* side-by-side background="dark-secondary" shapes="polygons" */}

#### DARK VARIANT
## Dark-secondary _background_
On dark backgrounds, the text automatically becomes white.
{/* icon="arrow-right" */}
[View more](/en/docs)
---DARK VARIANT
On dark backgrounds, the text automatically becomes white.
View more{/* side-by-side shapes="hexagon,dots" */}
#### DIAGRAM • SIDE-BY-SIDE
## Diagram next to text
Place a mermaid diagram in the media slot instead of an image. Because the diagram sits below the text, it appears on the right.
{/* background="dark-secondary" */}
```mermaid
flowchart TD
A[Request] --> B{In cache?}
B -->|Yes| C[From cache]
B -->|No| D[Fetch]
D --> E[Store]
```
{/* icon="arrow-right" */}
[More information](/en/docs)
---Result:
DIAGRAM • SIDE-BY-SIDE
Place a mermaid diagram in the media slot instead of an image. Because the diagram sits below the text, it appears on the right.
More information{/* side-by-side background="light-grey" shapes="polygons" */}
{/* background="dark-gray" */}
```typescript
export function greet(name: string) {
return `Hello, ${name}!`;
}
```
#### CODE • SIDE-BY-SIDE
## Code block next to text
A code block can also fill the media slot. Because the code block sits above the text, it appears on the left.
---Result:
CODE • SIDE-BY-SIDE
A code block can also fill the media slot. Because the code block sits above the text, it appears on the left.
export function greet(name: string) {
return `Hello, ${name}!`;
}Displays feature content in a card grid or — with variant="list" — as a scrollable list with a detail panel. Both variants support optional background patterns.
| Prop | Values |
|---|---|
gridPattern | left, right, both, none |
variant | list (optional; without variant = card grid) |
| Prop | Values |
|---|---|
icon | settings, pencil, arrow-right, etc. |
#### — Overline## — Title (supports *emphasis*){/* feature icon="..." */} — Start of each card### — Card title[text](url) — Optional card link{/* icon="arrow-right" */}) — Section action{/* feature-section gridPattern="both" */}
#### Documentation example
## How we can _help_
{/* feature icon="settings" */}
### Software development
Donec condimentum sit amet magna vel tincidunt. Sed ullamcorper tortor.
[View cases](/en/cases)
{/* feature icon="pencil" */}
### Ongoing development
Donec condimentum sit amet magna vel tincidunt. Sed ullamcorper tortor.
[View cases](/en/cases)
{/* feature icon="arrow-right" */}
### Support & maintenance
Donec condimentum sit amet magna vel tincidunt. Sed ullamcorper tortor.
[View cases](/en/cases)
{/* icon="arrow-right" */}
[Discover our services](/en/services)
---Documentation example
Donec condimentum sit amet magna vel tincidunt. Sed ullamcorper tortor.
Donec condimentum sit amet magna vel tincidunt. Sed ullamcorper tortor.
Donec condimentum sit amet magna vel tincidunt. Sed ullamcorper tortor.
variant="list")Use the same {/* feature-section ... */} directive with variant="list". Sub-sections keep the name {/* feature icon="..." */}.
#### — Overline (section)## — Title (section, supports *emphasis*){/* feature icon="..." */} — Start of each list item#### — Item subtitle (shown in list and detail panel)### — Item title[text](url) — Optional item link{/* icon="arrow-right" */}) — Section action{/* feature-section variant="list" gridPattern="both" */}
#### Documentation example
## How we can _help_
{/* feature icon="settings" */}
#### From idea to working application
### Software development
We build custom software that fits seamlessly with your processes.
[View our projects](/en/cases)
{/* feature icon="pencil" */}
#### Improve existing systems
### Software ongoing development
Existing applications deserve attention. We modernise legacy systems and add new functionality.
[More about ongoing development](/en/cases)
{/* feature icon="wrench" */}
#### Always up to date and stable
### Support & maintenance
Your software stays in good hands with proactive maintenance and short lines for support.
[Discover our support team](/en/cases)
{/* icon="arrow-right" */}
[Discover our services](/en/services)
---Documentation example
We build custom software that fits seamlessly with your processes.
Existing applications deserve attention. We modernise legacy systems and add new functionality.
Your software stays in good hands with proactive maintenance and short lines for support.
From idea to working application
We build custom software that fits seamlessly with your processes.
Displays a tabbed section with technology categories. Each tab has a left column (title and introduction text), a dark card with bullet points, and a row of technology logos. On the homepage this block usually sits directly under Feature Section; use overlapPrevious="false" when there is no section above that needs to connect visually.
| Prop | Values | Default |
|---|---|---|
titleEmphasis | text | — |
buttonText | text | Bekijk alle |
buttonHref | URL | /technologie |
overlapPrevious | true, false | true |
Before the first {/* technology */} (section intro):
#### — Overline## — Title (without emphasis; use titleEmphasis for the italic part)Per technology tab (repeat {/* technology */}):
Attribute on {/* technology ... */} | Description |
|---|---|
label | Tab label in the tab bar |
leftTitle | Title in the left column when this tab is active |
Markdown per tab:
### — Title on the dark card (cardTitle)leftDescription)- list — Bullet points on the card; use an em dash (—) between title and description, e.g. - Title — Description — Technology logos (one or more images at root level, not indented under a list item){/* technology-section overlapPrevious="false" titleEmphasis="technologieën" buttonText="Bekijk alle" buttonHref="/technologie" */}
#### how we do that
## Our
Donec condimentum sit amet magna vel tincidunt. Sed ullamcorper tortor.
{/* technology label="Back-end" leftTitle="Back-end" */}
### Lorem ipsum dolor
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Donec condimentum sit amet magna vel tincidunt.
- Solid technical foundation — Robust systems that grow with you.
- Proactive monitoring — Real-time insight into performance.


{/* technology label="Front-end" leftTitle="Front-end" */}
### Modern interfaces
Our front-end specialists build fast, accessible interfaces.
- Modern frameworks — React, Vue, Angular, and Qwik.
- Performance optimisation — Fast load times on every device.


---how we do that
Donec condimentum sit amet magna vel tincidunt. Sed ullamcorper tortor.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Donec condimentum sit amet magna vel tincidunt.
A carousel with testimonials (quote, avatar, name, and role). The background grid pattern is configurable; autoplay is optional.
Each testimonial starts with {/* testimonial */} (similar to {/* feature */} in Feature Section). There is no section intro before the first testimonial: place {/* testimonial-carousel ... */} directly, followed by {/* testimonial */} and the markdown per slide.
| Prop | Values | Default |
|---|---|---|
gridPattern | left, right, both, none | — |
autoplayEnabled | true, false | — (autoplay off) |
autoplayInterval | milliseconds as a string, e.g. 6000 | 5000 when autoplay is on |
## — Quote (supports *emphasis*) — Avatar image### — Name{/* testimonial-carousel gridPattern="both" */}
{/* testimonial */}
## 10KB delivers exactly what they promise — and more.

### Alex de Vries
CTO at Example Ltd
{/* testimonial */}
## Second testimonial with _emphasis_.

### Jamie Jansen
Product owner
---Alex de Vries
CTO at Example Ltd
Jamie Jansen
Product owner
Code blocks automatically get syntax highlighting via Shiki. Adjust the background colour, width, and decorative shapes with a comment above the block.
| Prop | Values | Default |
|---|---|---|
background | dark-gray, light-grey, white, dark-secondary, dark-primary | dark-gray |
contentWidth | proseWide | prose (720px) |
shapes | tech, dots, hexagon, polygons | — |
typescript, javascript, jsx, tsx, css, html, json, bash, shell, yaml, markdown, python, sql, diff, text
```typescript
const greeting: string = "Hello, world!";
function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(greet("10KB"));
```const greeting: string = "Hello, world!";
function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(greet("10KB"));{/* background="light-grey" */}
```typescript
interface User {
id: number;
name: string;
email: string;
}
const user: User = {
id: 1,
name: "Ewout",
email: "ewout@10kb.nl",
};
```interface User {
id: number;
name: string;
email: string;
}
const user: User = {
id: 1,
name: "Ewout",
email: "ewout@10kb.nl",
};{/* background="dark-primary" shapes="hexagon" */}
```css
.container {
display: flex;
flex-direction: column;
gap: 1.5rem;
max-width: 720px;
margin: 0 auto;
}
@media (min-width: 768px) {
.container {
flex-direction: row;
}
}
```.container {
display: flex;
flex-direction: column;
gap: 1.5rem;
max-width: 720px;
margin: 0 auto;
}
@media (min-width: 768px) {
.container {
flex-direction: row;
}
}{/* background="dark-gray" shapes="tech" contentWidth="proseWide" */}
```javascript
async function fetchData(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
}
const data = await fetchData("/api/users");
console.log(data);
```async function fetchData(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
}
const data = await fetchData("/api/users");
console.log(data);{/* background="dark-gray" shapes="polygons" */}
```typescript
export type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };
function divide(a: number, b: number): Result<number> {
if (b === 0) return { ok: false, error: new Error("Division by zero") };
return { ok: true, value: a / b };
}
```export type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };
function divide(a: number, b: number): Result<number> {
if (b === 0) return { ok: false, error: new Error("Division by zero") };
return { ok: true, value: a / b };
}{/* background="light-grey" shapes="dots" */}
```json
{
"name": "website",
"version": "1.0.0",
"dependencies": {
"@builder.io/qwik": "^1.12.1",
"@builder.io/qwik-city": "^1.12.1"
}
}
```{
"name": "website",
"version": "1.0.0",
"dependencies": {
"@builder.io/qwik": "^1.12.1",
"@builder.io/qwik-city": "^1.12.1"
}
}{/* background="white" */}
```bash
# Install dependencies and start the dev server
npm install
npm run dev
# Build for production
npm run build
npm run preview
```# Install dependencies and start the dev server
npm install
npm run dev
# Build for production
npm run build
npm run preview{/* background="dark-secondary" */}
```typescript
import { component$, useSignal } from "@builder.io/qwik";
export const Counter = component$(() => {
const count = useSignal(0);
return (
<div>
<p>Count: {count.value}</p>
<button onClick$={() => count.value++}>Increment</button>
</div>
);
});
```import { component$, useSignal } from "@builder.io/qwik";
export const Counter = component$(() => {
const count = useSignal(0);
return (
<div>
<p>Count: {count.value}</p>
<button onClick$={() => count.value++}>Increment</button>
</div>
);
});Mermaid diagrams are written as a ```mermaid code block. During development (pnpm dev) a headless browser converts them to a static SVG that is stored in the repository (src/assets/mermaid/). The production and CI build only read that stored SVG and never start a browser. Background and decorative shapes work exactly like the Code Block: via a comment above the block.
If the SVG is missing during a production build, the build fails with a clear message. Run pnpm dev or pnpm mermaid:render locally and commit the generated file.
| Prop | Values | Default |
|---|---|---|
background | dark-gray, light-grey, white, dark-secondary, dark-primary | dark-gray |
contentWidth | proseWide | prose (720px) |
shapes | tech, dots, hexagon, polygons | — |
title | Accessible description of the diagram | — |
```mermaid
flowchart LR
A[Start] --> B{Decision}
B -->|Yes| C[OK]
B -->|No| D[Stop]
```Result:
{/* background="dark-primary" shapes="hexagon" title="Deploymentflow" */}
```mermaid
sequenceDiagram
participant Dev
participant CI
participant Prod
Dev->>CI: Push commit
CI->>Prod: Deploy build
Prod-->>Dev: Status
```Result:
{/* background="light-grey" */}
```mermaid
flowchart TD
A[Idee] --> B[Ontwerp]
B --> C[Implementatie]
C --> D[Release]
```Result:
An extended diagram with subgraphs, different shapes (stadium, parallelogram, diamond, subroutine, database, hexagon, asymmetric), various arrow types (normal, dotted, thick), and classDef styling.
{/* background="dark-secondary" shapes="polygons" contentWidth="proseWide" title="Verwerkingspijplijn" */}
```mermaid
flowchart TB
Start([Start]) --> Input[/Input/]
Input --> Validate{Valid?}
Validate -->|No| Error[[Error handling]]
Validate -->|Yes| Process
subgraph Process [Processing]
direction LR
Load[(Database)] --> Transform[Transform]
Transform --> Cache{{Cache}}
Cache -.-> Queue[/Queue/]
end
Process ==> Decision{Done?}
Decision -->|No| Retry(Try again)
Retry --> Process
Decision -->|Yes| Report[Report]
Report --> Notify>Notification]
Notify --> Done([End])
Error --> Done
classDef success fill:#023020,stroke:#0a5c3e,color:#fff;
classDef danger fill:#a47b0f,stroke:#e2aa14,color:#fff;
class Done,Report success;
class Error danger;
```Result:
Images in the body can be given decorative shapes via a variant prop.
| Prop | Values |
|---|---|
variant | rhombus-left-arrow-right, arrow-left-hexagon-right |
contentWidth | proseWide |
{/* variant="rhombus-left-arrow-right" */}
{/* variant="arrow-left-hexagon-right" */}
{/* variant="rhombus-left-arrow-right" contentWidth="proseWide" */}
A highlighted quote with an optional author and role.
| Prop | Values |
|---|---|
author | text |
role | text |
contentWidth | proseWide |
{/* pull-quote author="Ewout" role="Founder 10KB" */}
> Software development is a continuous process of improvement and innovation. A dedicated team that understands your domain makes the difference.Software development is a continuous process of improvement and innovation. A dedicated team that understands your domain makes the difference.
Ewout — Founder 10KB
{/* pull-quote author="Google DeepMind" role="Productaankondiging" contentWidth="proseWide" */}
> Gemini 2.5 Pro leads industry benchmarks for coding, maths, and science and is now widely available via the Gemini API.Gemini 2.5 Pro leads industry benchmarks for coding, maths, and science and is now widely available via the Gemini API.
Google DeepMind — Productaankondiging
A styled list with bold titles and descriptions, used for summaries or feature overviews.
{/* article-list */}
- **Server-side rendering** All syntax highlighting runs server-side via Shiki, without JavaScript in the browser.
- **Comment syntax** Components are controlled via JSX comments; no imports needed.
- **Automatic theme detection** Dark backgrounds automatically get a dark colour scheme and vice versa.Server-side rendering
All syntax highlighting runs server-side via Shiki, without JavaScript in the browser.
Comment syntax
Components are controlled via JSX comments; no imports needed.
Automatic theme detection
Dark backgrounds automatically get a dark colour scheme and vice versa.
A prominent block with the key points, closed by a horizontal rule.
| Prop | Values | Default |
|---|---|---|
contentWidth | default, proseWide | default |
{/* key-takeaways contentWidth="default" */}
## Key _takeaways_
- All components use the comment syntax for configuration
- Section components are closed with ---
- Background colours and shapes are available for multiple components
- Image position in SideBySide is determined automatically
---All components use the comment syntax for configuration
Section components are closed with ---
Background colours and shapes are available for multiple components
Image position in SideBySide is determined automatically
Displays a background image with a dark-to-transparent gradient, grid pattern, and content on a configurable side. The first paragraph is shown in bold as lead text.
| Prop | Values | Default |
|---|---|---|
grid | true, false | true |
align | left, right | left |
 — Background image#### — Overline## — Title (supports *emphasis*)- list — Bullet list (optional, supports **bold** labels)[text](url) — Action link (with optional {/* icon="arrow-right" */}){/* showcase */}

#### TECHNIQUE 1 • TECHNIQUE 2 • TECHNIQUE 3
## Added value as a dedicated IT _partner_
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque sed lacus ultrices, blandit elit vitae, imperdiet tortor.
Donec condimentum sit amet magna vel tincidunt. Sed ullamcorper tortor maximus, dignissim urna vulputate, tempor libero. Nunc hendrerit diam eu diam eleifend efficitur ut id mauris.
{/* icon="arrow-right" */}
[Read more](/en/cases)
---TECHNIQUE 1 • TECHNIQUE 2 • TECHNIQUE 3
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque sed lacus ultrices, blandit elit vitae, imperdiet tortor.
Donec condimentum sit amet magna vel tincidunt. Sed ullamcorper tortor maximus, dignissim urna vulputate, tempor libero. Nunc hendrerit diam eu diam eleifend efficitur ut id mauris.
Read more{/* showcase align="right" */}

#### SOFTWARE DEVELOPMENT
## Mission critical _software_
We build software that is reliable, secure, and scalable.
Donec condimentum sit amet magna vel tincidunt. Sed ullamcorper tortor maximus.
{/* icon="arrow-right" */}
[Discover our services](/en/services)
---SOFTWARE DEVELOPMENT
We build software that is reliable, secure, and scalable.
Donec condimentum sit amet magna vel tincidunt. Sed ullamcorper tortor maximus.
Discover our servicesDisplays an accordion with frequently asked questions, optional introduction text, and an optional action button. The section is closed with a horizontal rule.
Use a lowercase letter in the opening comment: {/* faq ... */}. Comments such as {/* FAQ ... */} are not recognised as a directive.
| Prop | Values | Default |
|---|---|---|
contentWidth | default, proseWide | default |
background | white, light-grey | white |
Use background="light-grey" when the FAQ directly follows key takeaways. The background spans the full width, while questions and answers stay on white surfaces.
{/* faq ... */} — Optional contentWidth and background (such as background="light-grey").## — Section title (supports *emphasis*).### — Optional introduction (subheader).### — Question; following paragraphs and lists until the next ### — Answer.{/* icon="arrow-right" */} and a link to the action (CTA).--- — End of section.{/* faq contentWidth="default" background="light-grey" */}
## Frequently asked _questions_
Short intro before the questions.
### First question?
Here is the answer. With a [link](/en/docs).
### Second question?
Another answer.
Still not found?
{/* icon="arrow-right" */}
[Get in touch](/en/contact)
---Short intro before the questions.
Here is the answer. With a link.
Another answer.
Still not found?
Get in touchDisplays a carousel of case study cards next to an introduction column. The directive describes the selection intent; card copy, assets, and ordering come from the central case registry.
| Prop | Values | Default |
|---|---|---|
placement | home, generic, context | required unless context is set |
context | a controlled context tag from W03 | — |
limit | positive integer | 6, context defaults to 3 |
autoplay | true, false | — (from component: autoplay off) |
interval | milliseconds as an integer | 5000 (when autoplay is set) |
#### — Overline## — Title (supports *emphasis* in the Markdown source)--- — End of the carouselDo not add authored {/* case */} blocks. The registry only supplies cases
that pass the publication gate for the locale and placement. The /en/cases
overview uses {/* case-overview */} instead of this carousel.
{/* case-study-carousel placement="generic" limit="6" */}
#### OUR WORK
## Cases we are _proud_ of
First intro paragraph.
Second intro paragraph.
---OUR WORK
First intro paragraph.
Second intro paragraph.
{/* case-study-carousel placement="generic" limit="6" autoplay="true" interval="6000" */}
#### CAROUSEL
## With _autoplay_
Short intro.
---CAROUSEL
Short intro.
Shows all published cases on /en/cases as alternating side-by-side sections.
Order, copy, assets, and the rotation of background and image position come
from the central case registry. The page only authors the directive; there
are no extra props.
{/* case-overview */}--- — End of the listing{/* case-overview */}
---Displays a vertical timeline of historical milestones. Each milestone has a year, a title, and a short description. The section is closed with a horizontal rule.
| Prop | Values | Default |
|---|---|---|
background | white, light-grey, dark-secondary, dark-primary, dark-gray | white |
shapes | comma-separated: hexagon, dots, rhombus, arrow, polygons | — |
#### — Overline (optional)## — Title (supports _emphasis_){/* milestone year="..." */} — Start of each milestone; year is required (free text, for example 2012, 2012–2014, or Now)### — Milestone title (required)--- — End of the sectionOn a dark background the text colour switches automatically.
{/* timeline background="light-grey" shapes="hexagon,dots" */}
#### Documentation example
## Our _history_
A short timeline of moments that shaped the company.
{/* milestone year="2012" */}
### The agency starts
A compact development team that builds software meant to last.
{/* milestone year="2016" */}
### The team grows
More specialists, the same way of working, and the same focus on quality.
{/* milestone year="Now" */}
### Ongoing collaboration
Long-term partnerships instead of one-off projects.
---Documentation example
A short timeline of moments that shaped the company.
2012
A compact development team that builds software meant to last.
2016
More specialists, the same way of working, and the same focus on quality.
Now
Long-term partnerships instead of one-off projects.
Every MDX page starts with frontmatter. Three layouts are available: page, blog, and blog-overview. The blog layout has an extensive plugin system that calculates and inherits fields automatically, and the blog-overview uses that same data to show child pages automatically.
The URL on which an MDX page is served is derived automatically from the file location within pages/, with the exception of the special pages/home/ directory.
The rules (in order of priority):
url (or slug) in frontmatter — when present this wins, with leading/trailing slashes stripped. This is the escape hatch to override the directory-based URL (e.g. url: /other-url or a locale-specific URL slug: /en/blog/my-article). Both keys work the same; url takes precedence when both are present.pages/home/ directory — files in this directory are served at the site root instead of under the directory name. The default-locale file (nl.mdx) lands on /, every other locale on /<locale> (e.g. en.mdx → /en). These pages automatically get inBreadcrumbs: false.pages/blog/post/nl.mdx → /blog/post.| File | URL |
|---|---|
pages/home/nl.mdx | / |
pages/home/en.mdx | /en |
pages/diensten/nl.mdx | /diensten |
pages/blog/post/nl.mdx | /blog/post |
pages/blog/post/en.mdx (with slug: /en/blog/post) | /en/blog/post |
pages/diensten/maatwerk/nl.mdx (with url: /software-op-maat) | /software-op-maat |
---
layout: page
title: Page title
description: Meta description for SEO.
------
layout: blog
title: Blog title - 10KB
heroTitle: "Title with\nline break and *emphasis*"
description: Meta description for SEO.
image: ~/assets/photos/afbeelding.png
authorName: Ewout
date: 2026-01-15
tags: [continuity, software-development]
------
layout: blog-overview
overviewType: blog
title: 10KB Blog - 10KB
heroTitle: "Insights on *software development*"
description: Articles from 10KB about software development, DevOps, and custom software.
---| Field | Layout | Description |
|---|---|---|
layout | all | page, blog, or blog-overview |
title | all | Page title (SEO) |
description | all | Meta description |
url | all | Override the directory-based URL (e.g. /software-op-maat). Alias of slug; url takes precedence. |
heroTitle | blog | Hero title with *emphasis* and \n line break. Falls back to title. |
image | blog | Hero image, supports ~/assets/... paths |
authorName | blog | Author name |
date | blog | Publication date (YYYY-MM-DD) |
tags | blog | Array of tags, used for related articles |
showcase | blog | Boolean that places a blog article in the showcase stream of the blog-overview |
slug | blog | URL path for locale-specific pages (e.g. /en/blog/my-article) |
inheritKeys | blog | Override which fields are inherited (see Locale inheritance) |
overviewType | blog-overview | Type of overview page, currently blog |
These fields are calculated by frontmatter plugins and do not need to be set by hand.
| Field | Source | Description |
|---|---|---|
locale | filename | Derived from the filename: nl.mdx → "nl", en.mdx → "en" |
readTime | content | Calculated from word count (words ÷ 200, minimum 1 minute). Code blocks are skipped. |
dateString | date + locale | Locale-aware formatting of date, e.g. "15 January 2026" for EN |
relatedArticles | tags | Generated automatically from shared tags. Shows up to 3 articles in the same language. Overline and title are translated automatically per locale. |
posts | overview-plugin | For blog-overview: flat list of direct child articles per locale, sorted by date (newest first), used by the client-side filters |
inBreadcrumbs | pages/home/ dir | Automatically false for pages in pages/home/. Can be overridden manually by setting inBreadcrumbs explicitly in frontmatter. |
Blog articles support automatic field inheritance between language versions. Files in the same directory are linked to each other.
How it works:
slug field, e.g. nl.mdx) is the sourceslug field, e.g. en.mdx) inherit missing fieldsDefault inherited fields: image, authorName, tags, date
This means you only need to set these fields in the default file; translations inherit them automatically.
Example — default file (nl.mdx):
---
layout: blog
title: Hoe continuïteit waarde creëert - 10KB
heroTitle: "Hoe continuïteit waarde\ncreëert voor *bedrijven*"
description: Ontdek hoe continuïteit in software ontwikkeling waarde creëert.
image: ~/assets/photos/continuity.png
authorName: Ewout
date: 2026-01-15
tags: [continuity, software-development]
---Example — locale-specific file (en.mdx in the same directory):
---
layout: blog
slug: /en/blog/how-continuity-creates-value
title: How Continuity Creates Value - 10KB
heroTitle: "How continuity creates\nvalue for *businesses*"
description: Discover how continuity in software development creates value.
---The English file automatically inherits image, authorName, tags, and date from nl.mdx.
Override: Set inheritKeys to control which fields are inherited:
---
inheritKeys: [image, date]
---Frontmatter plugins run in two phases:
| Phase | Plugin | Action |
|---|---|---|
| 1 — per file | localePlugin | Derives locale from filename |
| 1 — per file | readTimePlugin | Calculates readTime from word count |
| 1 — per file | homeBreadcrumbPlugin | Sets inBreadcrumbs: false for pages/home/ |
| 2 — cross-file | localeInheritPlugin | Inherits fields from the default locale |
| 2 — cross-file | breadcrumbPlugin | Builds breadcrumb crumbs and sibling dropdowns |
| 2 — cross-file | dateFormatPlugin | Formats date to dateString |
| 2 — cross-file | relatedArticlesPlugin | Generates related articles based on tags |
Phase 1 processes each file separately. Phase 2 runs across all files at once, so later plugins see data already enriched by earlier plugins.
CONTACT
Have a question or want to discuss your software? Leave your details and we will get back to you soon.