Content Definitions

Content definitions are the foundation of bserver. Every piece of content on a page comes from a YAML definition that maps a name to its content.

Plain Definitions

The simplest form maps a name to content:

main:
  - h1: "Page Title"
  - p: "Some content here."

When bserver encounters the name main, it looks up this definition and renders it as HTML.

The Four Prefixes

A YAML key is interpreted differently depending on its first character:

Prefix Name Purpose
(none) Content definition Sets the value of a name
^ Format definition Defines how a name renders as HTML
+ Merge definition Adds to an existing definition
$ Data source Runs a script to produce the value of a name

Content Definitions (plain keys)

footer:
  muted: This is the footer text

Plain keys define content. The first definition loaded wins — so your page-level definition overrides inherited ones from parent directories.

Format Definitions (^ prefix)

^muted:
  tag: div
  params:
    class: text-muted small
  content: '$*'

The caret ^ prefix registers a format definition that controls how a name renders as HTML. See Format Definitions for details.

Merge Definitions (+ prefix)

+headlink:
  - rel: stylesheet
    href: https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css

The + prefix merges into an existing definition rather than replacing it. This is how Bootstrap adds its stylesheet to the head section without overwriting other stylesheets.

Data Sources ($ prefix)

$navlinks:
  script: javascript
  code: |
    print(JSON.stringify([{key: "/", value: "Home"}]));

The $ prefix declares a script-backed content definition. When the name is needed, the script runs and its JSON output becomes the value. See Data Sources for details.

String Values

A string value can be either literal text or a name reference:

# Name reference - resolved to another definition
body:
  - header
  - main
  - footer

# Literal text - rendered as-is
title: My Website Title

Name references must start with a letter and contain only letters, digits, hyphens, and underscores. Anything else is treated as literal text:

String Type Why
header Name reference Letters only
nav-links Name reference Letters, hyphens
col2 Name reference Letters, digits
/about Literal text Starts with /
http://example.com Literal text Contains : and /
#333 Literal text Starts with #
logo.png Literal text Contains .
hello world Literal text Contains space

Lists

Lists define ordered content. Each item is rendered in sequence:

body:
  - header
  - main
  - footer

List items can be strings (name references or literal text), maps (inline tags), or nested lists.

Maps (Inline Tags)

When a map key matches an HTML tag or has a format definition, the value becomes the content inside that tag:

main:
  - h1: "Welcome"
  - p: "Hello world"
  - div: "A div with text"

Renders as:

<h1>Welcome</h1>
<p>Hello world</p>
<div>A div with text</div>

Maps can also nest:

main:
  - div:
      h1: "Title"
      p: "Paragraph inside the div"

Merge Behavior

The + prefix is powerful for composing definitions from multiple files.

Map Merge

For map definitions, new keys are added and existing keys are overridden:

# In base file:
meta:
  viewport: width=device-width, initial-scale=1

# In page file with +meta:
+meta:
  description: My page description

Result: meta has both viewport and description.

List Merge

For list definitions, items are appended:

# In base file:
headlink:
  - rel: stylesheet
    href: base.css

# In component file with +headlink:
+headlink:
  - rel: stylesheet
    href: bootstrap.min.css

Result: headlink has both stylesheet entries.

First Definition Wins

For plain content definitions (without +), the first definition loaded takes precedence:

# In your page's index.yaml:
title: My Page Title

# In a parent directory's title.yaml:
title: Default Title

Since bserver loads page-local files first, your page's title definition wins. This is how page-specific content overrides site-wide defaults.

File-Based Definitions

Each YAML file can contain multiple definitions. The filename determines when it's loaded:

For example, navbar.yaml contains both the navbar: content structure and all the ^navbar-* format definitions needed to render it.

Null/Empty Values

A key with no value (or explicit null) produces an empty element:

main:
  - hr:         # Self-closing <hr> tag
  - br:         # Self-closing <br> tag
  - div:        # Empty <div></div>

Void elements (like hr, br, img, meta, link) are automatically self-closing and never produce a closing tag.

Next Steps