Markdown Plugin

Markdown Plugin

Markdown Plugin

DesignerDesigner Agent Kit — documentation written for AI agents, readable by humans.

The @jay-framework/markdown plugin renders markdown content as HTML in jay-html pages. It provides three headless components.

Components

markdown-pages — Directory to pages

Scans a directory of .md files and provides page data. Each file becomes a routable page.

<script
  type="application/jay-headless"
  plugin="@jay-framework/markdown"
  contract="markdown-pages"
  key="post"
>
  contentDir: ./content
</script>

The component provides these ViewState fields (all slow phase):

  • {post.title} — title from frontmatter
  • {post.content} — rendered HTML
  • {post.description} — description from frontmatter
  • {post.date} — ISO date string
  • {post.tags} — array with {name} field (use with forEach)
  • {post.frontmatter} — full frontmatter as JSON string

SEO head tags (<title>, <meta description>, og:title, etc.) are injected automatically from frontmatter.

Images in markdown

Images referenced in markdown files (![alt](image.png)) are handled automatically:

Default (zero-config): Images alongside .md files in the content directory are copied to the project's public/ folder and URLs are rewritten to serve them as static assets. No props needed.

CDN hosting (with mediaMap): For optimized delivery, provide a mediaMap prop pointing to a YAML file that maps filenames to CDN URLs:

<script type="application/jay-headless" ...>
  contentDir: ./content
  mediaMap: ./media-map.yaml
</script>

The mapping file supports srcset for responsive images:

# media-map.yaml — generated by an upload script
'diagram.png':
  src: 'https://cdn.example.com/w_800/diagram.webp'
  width: 800
  height: 600
  srcset:
    - url: 'https://cdn.example.com/w_400/diagram.webp'
      width: 400
    - url: 'https://cdn.example.com/w_800/diagram.webp'
      width: 800
    - url: 'https://cdn.example.com/w_1200/diagram.webp'
      width: 1200

Mapped images render with srcset, sizes, width, height, and loading="lazy". Unmapped images fall back to the default local serving. The mapping file is typically generated by an external upload script — not hand-written.

markdown-content — Static inline renderer

Renders a markdown string at build time. Use for static content embedded in a page.

<jay:markdown-content markdown="{myMarkdownField}">
  <div class="md">{html}</div>
</jay:markdown-content>

markdown-live — Dynamic renderer

Renders markdown that can change at request time or on the client. Ships the parser to the browser.

<jay:markdown-live markdown="{dynamicContent}">
  <div class="md">{html}</div>
</jay:markdown-live>

Markdown File Format

---
title: Getting Started
date: 2026-07-15
description: A guide to getting started
author: Jane Doe
tags: [tutorial, beginner]
---

# Getting Started

Your content here with **bold**, _italic_, and [links](https://example.com).

Frontmatter Fields

Field Purpose Auto-injected as
title Page title <title>, og:title
description SEO description <meta description>, og:description
date Publish date article:published_time
author Author name <meta author>
image Cover image og:image
canonical Canonical URL <link canonical>

Any other field (e.g., category: guides) becomes <meta name="category" content="guides">.

Code Highlighting

Code fences are highlighted with CSS classes. Supported languages: JavaScript/TypeScript, HTML, CSS, YAML, JSON, Bash, Python.

```typescript
const hello = 'world';
```

Output structure

<pre class="md-code">
  <code class="language-typescript">
    <span class="token keyword">const</span> hello = <span class="token string">'world'</span>;
  </code>
</pre>

CSS classes

Class Element Purpose
.md-code <pre> Code block container
.language-{lang} <code> Language identifier (e.g., .language-typescript)

Token classes (inside <code>)

Class Colors in default theme Used for
.token.keyword #8b5cf6 (purple) const, function, if, return, import, def, class
.token.string #059669 (green) 'hello', "world", `template`
.token.comment #94a3b8 (gray, italic) // comment, /* block */, # comment
.token.number #d97706 (amber) 42, 3.14, 16px
.token.function #2563eb (blue) greet(, console.log(
.token.operator #64748b (slate) =, +, =>, &&
.token.punctuation #94a3b8 (gray) {}, (), ;, ,
.token.tag #dc2626 (red) HTML tags: <div, </span
.token.attribute #d97706 (amber) HTML attributes: class=, href=

Mermaid Diagrams

Mermaid fences are rendered to SVG on the server (via beautiful-mermaid). On the client (markdown-live), they output as source text for optional client-side rendering.

<div class="md-mermaid"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 263.77 116.9" width="263.77" height="116.9">
<style>
  svg {
    /* Derived from --bg and --fg (overridable via --line, --accent, etc.) */
    --_text:          var(--fg);
    --_text-sec:      var(--muted, color-mix(in srgb, var(--fg) 60%, var(--bg)));
    --_text-muted:    var(--muted, color-mix(in srgb, var(--fg) 40%, var(--bg)));
    --_text-faint:    color-mix(in srgb, var(--fg) 25%, var(--bg));
    --_line:          var(--line, color-mix(in srgb, var(--fg) 50%, var(--bg)));
    --_arrow:         var(--accent, color-mix(in srgb, var(--fg) 85%, var(--bg)));
    --_node-fill:     var(--surface, color-mix(in srgb, var(--fg) 3%, var(--bg)));
    --_node-stroke:   var(--border, color-mix(in srgb, var(--fg) 20%, var(--bg)));
    --_group-fill:    var(--bg);
    --_group-hdr:     color-mix(in srgb, var(--fg) 5%, var(--bg));
    --_inner-stroke:  color-mix(in srgb, var(--fg) 12%, var(--bg));
    --_key-badge:     color-mix(in srgb, var(--fg) 10%, var(--bg));
  }
</style>
<defs>
  <marker id="arrowhead" markerWidth="8" markerHeight="5" refX="7" refY="2.5" orient="auto">
    <polygon points="0 0, 8 2.5, 0 5" fill="var(--_arrow)" stroke="var(--_arrow)" stroke-width="0.75" stroke-linejoin="round" />
  </marker>
  <marker id="arrowhead-start" markerWidth="8" markerHeight="5" refX="1" refY="2.5" orient="auto-start-reverse">
    <polygon points="8 0, 0 2.5, 8 5" fill="var(--_arrow)" stroke="var(--_arrow)" stroke-width="0.75" stroke-linejoin="round" />
  </marker>
</defs>
<polyline class="edge" data-from="A" data-to="B" data-style="solid" data-arrow-start="false" data-arrow-end="true" points="110.108,58.45 158.108,58.45" fill="none" stroke="var(--_line)" stroke-width="1" marker-end="url(#arrowhead)" />
<g class="node" data-id="A" data-label="Start" data-shape="rectangle">
  <rect x="40" y="40" width="70.108" height="36.900000000000006" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
  <text x="75.054" y="58.45" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">Start</text>
</g>
<g class="node" data-id="B" data-label="End" data-shape="rectangle">
  <rect x="158.108" y="40" width="65.662" height="36.900000000000006" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
  <text x="190.93900000000002" y="58.45" text-anchor="middle" font-size="13" font-weight="500" fill="var(--_text)" dy="4.55">End</text>
</g>
</svg></div>

Output structure

Server (markdown-pages, markdown-content):

<div class="md-mermaid">
  <svg>...</svg>
</div>

Client fallback (markdown-live):

<div class="md-mermaid">
  <pre class="md-mermaid-source">
graph LR
  A[Start] --> B[End]</pre
  >
</div>

CSS classes

Class Element Purpose
.md-mermaid <div> Mermaid diagram container (centered, with margin)
.md-mermaid svg <svg> The rendered SVG diagram (max-width: 100%)
.md-mermaid-source <pre> Raw mermaid source (client fallback only)
.md-mermaid-error <pre> Error message when rendering fails

Theming mermaid diagrams

SVG diagrams use CSS custom properties for all colors. Set --bg and --fg on .md-mermaid svg to control the color scheme:

.md-mermaid svg {
  --bg: var(--color-surface);
  --fg: var(--color-text);
  font-family: inherit;
}

The SVG internally derives all colors from --bg and --fg:

Variable Derived from Controls
--_text --fg Node labels, actor names
--_line --fg 50% + --bg Edges, lifelines
--_arrow --fg 85% + --bg Arrow heads
--_node-fill --fg 3% + --bg Node backgrounds
--_node-stroke --fg 20% + --bg Node borders
--_group-fill --bg Subgraph backgrounds

Override individual variables for fine control:

.md-mermaid svg {
  --bg: #0a0a0a;
  --fg: #e4e4e7;
  --accent: #8b5cf6; /* arrow color */
  --surface: #1a1a2e; /* node fill */
  --border: #333; /* node stroke */
}

Theme CSS

Import a theme in your project CSS:

@import '@jay-framework/markdown/themes/markdown-blog.css';

Available themes:

  • markdown-default.css — clean, neutral
  • markdown-docs.css — documentation style (narrower, tighter)
  • markdown-blog.css — blog style (wider body text, generous spacing)

Override via CSS custom properties:

.md {
  --md-color-link: var(--accent);
  --md-color-heading: var(--text-primary);
  --md-color-code-bg: var(--bg-secondary);
}

About this document

This page is part of the Jay Stack Agent Kit — documentation generated from the framework source and written primarily for AI agents. The language and structure are optimized for machine consumption — expect precise, specification-style prose rather than narrative documentation. Learn more about the Agent Kit →