Skip to content
Get started

Narrative

zigzag, markdown-prose, timeline, steps-panel and faq — sections that carry an argument.

zigzag

Alternating text and image rows. The standard way to explain three or four things in sequence without a wall of prose.

zigzag

How it works

Point the engine at a folder

One config object names your content directory. Zellij reads everything else from what it finds there.

See the content model

Write sections, not components

A section is a YAML file with a type and some fields. Pages list the ones they want, in order.

body accepts inline markdown — bold, italic, code spans and links. Not block markdown: for that, use markdown-prose or a guide page.

markdown-prose

The escape hatch. Free-form prose inside marketing styling, for the page that needs a paragraph the tiles do not cover.

markdown-prose

Why we built Zellij

Every product site we shipped started the same way: a fresh Next.js app, a fortnight of layout work, and a design that drifted from the last one within a quarter.

The content was never the hard part. The scaffolding was. So we moved the scaffolding into a package and left the content in a folder.

A .md or .mdx file under sections/ is this type without saying so:

sections/home/story.md
---
background: tinted
---

## Why we build Acme

Operations teams deserve better than a spreadsheet with opinions.

timeline

A dated sequence: company history, a roadmap, milestones, the chapters of a book. Rendered as an ordered list, because that is what it is.

timeline

The story so far

A layout copied between three products, and then finally extracted.

  1. 2024

    The third copy-paste

    Same header, same footer, same section stack, diverging by the week.

  2. Q1 2026

    One package, three sites

    The layout moved into an engine and the products kept only their content.

  3. Q3 2026

    Documented by itself

    This page renders through the engine it documents.

date is free text, not a date type — 1984, Q3, Chapter one and Some time in the eighties all belong. A bare year is accepted and stringified, since YAML hands 2019 over as a number.

Items reveal from the side under subtle and expressive, which reads as the sequence assembling itself as you scroll.

steps-panel

Numbered steps on one side, the result they produce on the other. For a process where the outcome is a shape somebody needs to recognise — a folder, a schema, a directory tree — and a list of instructions alone would leave them guessing what they are working toward.

steps-panel

Four commands, and a folder that explains itself

The steps say what you run. The panel says what you end up with, so the two can be checked against each other without leaving the section.

  1. Write the folder

    zel new docs my-site puts eight files on disk — identity, a menu, a page and a guide. It writes files and exits; nothing is started.

  2. Watch it while you edit

    zel dev my-site mounts the folder into the engine and serves it. Every save is on screen before you have switched windows.

  3. Check before you build

    zel check my-site reads the whole folder and reports what is wrong with it, in about a second, without starting the application.

  4. Build what you deploy

    zel build my-site produces either a directory of static files or a container image, from the same content.

my-site
my-site/
├── site.yaml               ← identity and theme
├── menu.yaml               ← the bar
├── pages.yaml              ← pages, as section lists
├── sections/
│   └── home/hero.yaml      ← one band of content
└── 01-guide/
    ├── _sidebar.yaml       ← order and grouping
    └── index.mdx           ← a page

Nothing about the site lives outside this folder, which is why it travels between a laptop, a pipeline and a container unchanged.

The numbers are drawn from the list's own counter and never authored. Writing 01, 02 into the titles works right up until a step is inserted in the middle, and a screen reader would read every number twice.

The panel is sticky beside the steps on a wide viewport, so it is still there at the last step; stacked on a narrow one, where pinning it would cover the steps below.

The panel takes one of three things: visual for an image, terminal for a transcript, or diagram for Mermaid source. The last is what the section was really built for — a sequence diagram beside a numbered legend, where the numbers on the arrows are the numbers down the list:

a mode of a CI pipeline, drawn and explained
type: steps-panel
media: left
diagram: |
  sequenceDiagram
      autonumber
      participant C as CI Runner<br/>ubuntu-latest
      participant S as GitHub Secrets<br/>encrypted store
      S->>C: inject SGIT_KEY
      C->>C: run-secure: decrypt
steps:
  - title: inject SGIT_KEY
    body: GitHub decrypts the repository secret into the job's environment.
  - title: run-secure — decrypt
    body: Derives the key with scrypt and decrypts every manifest-listed blob.

Up to twelve steps. The panel is sticky so it survives a long legend, but a legend that outruns a screen twice over has become an article, and an article belongs in a guide.

faq

An accordion of question and answer pairs.

faq

Reasonable questions

Do I have to write React?

No. A wrapper app is three files and under thirty lines, and none of it changes as your site grows.

Can I add my own section type?

Yes — registerSection takes a schema and a component, and the renderer picks it up.

What happens if a link points at nothing?

The build fails and names the file, rather than shipping a 404.

Built on <details>, so it expands and collapses with no JavaScript at all and is keyboard operable for free. Answers accept inline markdown.