The Component Model

Understanding Bengal's Component Model: Identity, Mode, and Data.

11 min read 2291 words

Bengal uses a Component Model to organize content. This aligns the backend (how files are stored) with the frontend (how themes render them).

Think of every page as a Component Instance.

Concept Terminology Schema Key Definition Example
Identity Type type What is it?
Determines Logic (Sorting) & Template Family.
blog,doc,api
Mode Variant variant How does it look?
Determines Visual State (CSS/Hero).
magazine,wide
Data Props props What data does it have?
Content passed to template (Frontmatter).
author,banner

1. Identity (Type)

The Type defines the fundamental nature of the content. It controls:

  • Sorting Logic: Blog posts sort by date; Docs sort by weight.
  • Template Selection:type: bloglooks forthemes/[theme]/templates/blog/.
  • URL Structure: Different types may have different URL patterns.

Available Types

Type Sorting Use Case
doc By weight Technical documentation, guides
blog By date (newest first) Blog posts, news, articles
page By weight Static pages (about, contact)
changelog By date Release notes
api By weight API reference documentation

Full Examples

---
title: Installation Guide
description: How to install and configure Bengal
weight: 10
type: doc
tags:
  - getting-started
  - installation
---

# Installation Guide

Follow these steps to install Bengal...

Line 5 is highlighted:type: doctells Bengal this is documentation content.

What happens:

  • Page sorted byweight(10) within its section
  • Uses templates fromtemplates/doc/
  • Appears in documentation navigation
---
title: Announcing Bengal 1.0
description: We're excited to announce the stable release
date: 2025-06-15
type: blog
tags:
  - announcement
  - release
category: news
author: Bengal Team
---

# Announcing Bengal 1.0

We're thrilled to share that Bengal 1.0 is now available...

Line 5 is highlighted:type: blogtells Bengal this is a blog post — sorted by date.

What happens:

  • Page sorted bydate(newest first)
  • Uses templates fromtemplates/blog/
  • Appears in blog feed and archives
  • Date is required and prominently displayed
---
title: About Us
description: Learn about our team and mission
type: page
---

# About Us

We're a team of developers passionate about documentation...

Line 4 is highlighted:type: pagetells Bengal this is a static page.

What happens:

  • Page sorted by weight if specified
  • Uses templates fromtemplates/page/
  • Not included in blog feeds or date-based archives
---
title: Bengal 0.2.0
description: Major performance improvements and new features
type: changelog
date: 2025-06-01
weight: 5
---

# Bengal 0.2.0

## New Features

- Incremental builds with 10x faster rebuilds
- New shortcode system...

Lines 4-5 are highlighted:type: changelogwithdatetells Bengal this is a release note.

What happens:

  • Page sorted by date within the releases section
  • Uses templates fromtemplates/changelog/
  • Formatted for release note presentation

2. Mode (Variant)

The Variant defines the visual presentation. It controls:

  • Data Attributes: Setsdata-variant="[name]"on the<body>for CSS targeting.
  • Partials: Selects specific components (e.g.,page-hero-magazine.html).
  • Layout Variations: Different visual treatments for the same content type.

Available Variants

Variant Effect Best For
standard Default clean layout Most content
editorial Enhanced typography, wider margins Long-form articles
magazine Visual-heavy, featured images Blog posts with media
overview Landing page style Section index pages
wide Full-width content area Code-heavy documentation
minimal Stripped-down, distraction-free Focus content

Full Examples

---
title: "The Future of Static Sites"
description: "Why static is making a comeback"
date: 2025-06-01
type: blog
variant: editorial
author: "Jane Smith"
---

# The Future of Static Sites

In an era of increasingly complex web applications, there's a
quiet revolution happening...

Line 6 is highlighted:variant: editorialapplies enhanced typography for long-form reading.

Visual effect:

  • Larger body text with better line height
  • Pull quotes styled distinctively
  • Wider content margins for readability
  • Optimized for long-form reading
---
title: "Building Beautiful Documentation"
description: "A visual guide to documentation design"
date: 2025-06-01
type: blog
variant: magazine
banner_image: "/images/hero-docs.jpg"
featured: true
---

# Building Beautiful Documentation

![Hero Image](/images/hero-docs.jpg)

Documentation doesn't have to be boring...

Lines 6-7 are highlighted:variant: magazinewithbanner_imagecreates a visual-first layout.

Visual effect:

  • Large hero image at top
  • Title overlaid on image or positioned dramatically
  • Visual-first layout
  • Cards and media prominently featured
---
title: Documentation
description: Complete Bengal documentation
weight: 100
type: doc
variant: overview
icon: book-open
---

# Documentation

Welcome to Bengal documentation! Choose a section to get started.

:::{child-cards}
:::

Line 6 is highlighted:variant: overviewcreates a landing page style with card navigation.

Visual effect:

  • Section-style header
  • Card grid for child pages
  • Navigation-focused layout
  • Less text, more visual navigation
---
title: API Reference
description: Complete API documentation
type: doc
variant: wide
---

# API Reference

## `bengal.core.Page`

\`\`\`python
@dataclass
class Page:
    """Represents a single content page."""
    source_path: Path
    content: str
    metadata: dict[str, Any]
    rendered_html: str = ""
    # ... many more fields
\`\`\`

Line 5 is highlighted:variant: wideprovides full-width content area for code-heavy docs.

Visual effect:

  • No sidebar or narrow margins
  • Code blocks have maximum width
  • Tables can be wider
  • Ideal for API reference with large code samples

3. Data (Props)

Props are the data you pass to the component. Any frontmatter field that isn'ttypeorvariantbecomes a prop.

In Markdown Files

Use flat frontmatter (all fields at top level):

---
title: "My Post"
description: "A description for SEO and previews"
author: "Jane Doe"
banner_image: "/images/hero.jpg"
featured: true
custom_field: "Any value you need"
---

Full Examples by Content Type

---
title: "10 Tips for Better Documentation"
description: "Practical advice from years of writing docs"
date: 2025-06-01
type: blog
author: "Jane Doe"
author_image: "/images/authors/jane.jpg"
author_bio: "Technical writer with 10 years of experience"
category: "Writing"
tags:
  - documentation
  - writing
  - best-practices
reading_time: "8 min"
featured: true
banner_image: "/images/posts/docs-tips.jpg"
---

Lines 6-17 are highlighted: all fields aftertypeare props — custom data available in templates.

In templates:

<img src="{{ page.author_image }}" alt="{{ page.author }}">
<span>{{ page.reading_time }} read</span>
{% if page.featured %}
  <span class="badge">Featured</span>
{% end %}
---
title: "Configuration Reference"
description: "All configuration options for Bengal"
weight: 30
type: doc
icon: settings
badge: "Updated"
badge_color: "green"
toc_depth: 3
show_edit_link: true
github_path: "docs/reference/configuration.md"
---

Lines 6-12 are highlighted: props customize appearance — icons, badges, navigation.

In templates:

{% if page.icon %}
  <i class="icon-{{ page.icon }}"></i>
{% end %}
{% if page.badge %}
  <span class="badge badge-{{ page.badge_color }}">
    {{ page.badge }}
  </span>
{% end %}
---
title: "E-Commerce Platform"
description: "Full-stack e-commerce solution"
date: 2025-03-15
type: page
project_url: "https://example.com"
github_url: "https://github.com/user/project"
technologies:
  - React
  - Node.js
  - PostgreSQL
  - Docker
status: "Production"
client: "Acme Corp"
thumbnail: "/images/projects/ecommerce-thumb.jpg"
gallery:
  - "/images/projects/ecommerce-1.jpg"
  - "/images/projects/ecommerce-2.jpg"
---

Lines 6-19 are highlighted: rich props for portfolio pages — URLs, arrays, any structure you need.

In templates:

<div class="tech-stack">
  {% for tech in page.technologies %}
    <span class="tech-badge">{{ tech }}</span>
  {% end %}
</div>
<a href="{{ page.project_url }}">View Live</a>
---
title: "Building Fast Static Sites"
description: "Conference talk about Bengal SSG"
date: 2025-09-15
type: page
event_name: "PyCon 2025"
event_url: "https://pycon.org/2025"
location: "San Francisco, CA"
slides_url: "/slides/building-fast-static-sites.pdf"
video_url: "https://youtube.com/watch?v=..."
duration: "45 minutes"
audience_level: "Intermediate"
topics:
  - Static Site Generation
  - Performance
  - Python
---

Lines 6-17 are highlighted: props for event/talk pages — links to slides, videos, event details.

In templates:

<p>Presented at <a href="{{ page.event_url }}">{{ page.event_name }}</a></p>
<p>Duration: {{ page.duration }}</p>
{% if page.video_url %}
  <a href="{{ page.video_url }}">Watch Recording</a>
{% end %}

Combining Type, Variant, and Props

Here's how all three work together in real examples:

---
title: "Migrating from WordPress to Bengal"
description: "A step-by-step guide to moving your blog"
type: blog
variant: magazine
date: 2025-06-01
author: "Alex Chen"
author_image: "/images/authors/alex.jpg"
banner_image: "/images/posts/wp-migration.jpg"
banner_alt: "WordPress to Bengal migration diagram"
category: "Tutorials"
tags:
  - migration
  - wordpress
  - tutorial
reading_time: "15 min"
difficulty: "Intermediate"
series: "Migration Guides"
series_order: 1
---

Lines 4-5 aretypeandvariant; lines 7-20 are props. All three working together:

  • type: blog— sorted by date, uses blog templates
  • variant: magazine— visual layout with hero image
  • Props — author info, metadata, series tracking
---
title: "Template Functions Reference"
description: "Complete reference for Bengal template functions"
type: doc
variant: wide
weight: 50
icon: function
badge: "v0.2+"
toc_depth: 4
show_source_links: true
api_version: "0.2.0"
related_pages:
  - /docs/reference/template-variables/
  - /docs/tutorials/custom-templates/
---

Lines 4-5 aretypeandvariant; lines 7-15 are props. All three working together:

  • type: doc— sorted by weight, uses doc templates
  • variant: wide— full-width for code examples
  • Props — versioning, related content links
---
title: "Getting Started"
description: "Everything you need to begin with Bengal"
type: doc
variant: overview
weight: 10
icon: rocket
show_child_cards: true
card_columns: 2
featured_page: "/docs/get-started/quickstart/"
section_color: "blue"
---

# Getting Started

Welcome! Choose where to begin based on your experience.

:::{child-cards}
:columns: 2
:::

Lines 4-5 aretypeandvariant; lines 7-12 are props. All three working together:

  • type: doc— this section contains documentation
  • variant: overview— landing page with card navigation
  • Props — card layout, section appearance

Cascading from Sections

Settypeandvariantonce in a section's_index.mdand all child pages inherit them:

# content/docs/_index.md
---
title: Documentation
description: Complete Bengal documentation
cascade:
  type: doc
  variant: standard
weight: 100
---

Lines 5-8 are highlighted: thecascadeblock setstypeandvariantfor all child pages automatically.

Now child pages don't need to specifytype:

# content/docs/installation.md (inherits type: doc)
---
title: Installation
weight: 10
---

Site Skeletons

Define entire site structures using Skeleton Manifests (bengal project skeleton apply).

name: blog
description: A blog with posts, tags, and categories
version: "1.0"

structure:
  - path: index.md
    type: blog
    variant: magazine
    props:
      title: My Blog
      description: Welcome to my blog

  - path: posts/first-post.md
    type: blog
    props:
      title: My First Blog Post
      date: "2025-06-01"
      tags:
        - welcome
        - introduction
      category: meta

  - path: about.md
    type: page
    variant: standard
    props:
      title: About
      description: Learn more about me

Highlighted lines: Index and posts usetype: blog(lines 7-8, 14); About page usestype: page(lines 24-25) — different template family.

name: docs
description: Technical documentation
version: "1.0"

structure:
  - path: _index.md
    type: doc
    cascade:
      type: doc
      variant: standard
    props:
      title: Documentation
      weight: 100

  - path: getting-started/_index.md
    type: doc
    variant: overview
    props:
      title: Getting Started
      weight: 10
      icon: rocket

Highlighted lines: Root setstype: docwith cascade (lines 7-10); Getting started overridesvariant: overview(line 17) for landing page style.

name: portfolio
description: Portfolio site with projects showcase
version: "1.0"

structure:
  - path: index.md
    type: page
    variant: home
    props:
      title: Portfolio
      description: Welcome to my portfolio

  - path: projects/_index.md
    props:
      title: Projects

  - path: projects/project-1.md
    type: page
    variant: project
    props:
      title: E-Commerce Platform
      featured: true
      technologies:
        - React
        - Node.js
      demo_url: https://example.com

Highlighted lines: Home page usesvariant: home(lines 7-8); Projects usevariant: project(lines 18-19) with rich props (lines 21-26).


Quick Reference

Field Purpose Examples
type What it is (logic + templates) doc,blog,page,changelog
variant How it looks (CSS + partials) standard,editorial,magazine,wide,overview
props Custom data for templates author,banner_image,featured, anything else

In Templates

{# Body tag uses data attributes and kind-based classes #}
<body data-type="{{ page.type }}" data-variant="{{ page.variant or '' }}"
      class="page-kind-{{ page.kind or 'page' }}">

{# Access props directly #}
<h1>{{ page.title }}</h1>
<p>By {{ page.author }}</p>
{% if page.featured %}
  <span class="badge">Featured</span>
{% end %}

CSS Targeting:

/* Target by variant */
body[data-variant="editorial"] { /* editorial styles */ }
body[data-variant="magazine"] { /* magazine styles */ }

/* Target by type */
body[data-type="blog"] { /* blog-specific styles */ }

Legacy Migration

If you are coming from older Bengal versions:

Old Field New Field Notes
layout variant Automatic normalization
hero_style variant Automatic normalization
metadatadict flat props Move fields to top level

The system automatically normalizes these for you—no changes required to existing content.