This project has been sunsetted and is no longer active. Follow what the developer is working on now at tylerberggren.com

Inline HTML

Write raw HTML directly in your markdown files. sitemd passes all HTML through to the final page with no sanitization or filtering — what you write is what renders.

Inline elements

Use HTML tags inside a paragraph alongside regular markdown:

This word is <mark>highlighted</mark> and this is <kbd>Ctrl+C</kbd>.

Water is H<sub>2</sub>O. The equation is E = mc<sup>2</sup>.

Use <abbr title="Hypertext Markup Language">HTML</abbr> when markdown isn't enough.

Common inline tags: <span>, <mark>, <kbd>, <abbr>, <sub>, <sup>, <small>, <del>, <ins>.

Block elements

Block-level HTML goes on its own line with blank lines above and below:

Some markdown text above.

<div style="padding: 1rem; border-left: 3px solid var(--accent); background: var(--bg-secondary);">
  <strong>Note:</strong> This is a custom callout box using theme CSS variables.
</div>

More markdown text below.

The blank lines are important — without them, markdown won't recognize where the HTML block starts and ends.

Collapsible sections

The <details> and <summary> elements create expandable sections:

<details>
<summary>Click to expand</summary>

This content is hidden by default. You can use **markdown** inside the details block — just leave a blank line after the `<summary>` tag.

- Lists work
- So do `code blocks`
- And [links](/)

</details>
Click to expand

This content is hidden by default. You can use markdown inside the details block — just leave a blank line after the <summary> tag.

  • Lists work
  • So do code blocks
  • And links

Add the open attribute to start expanded: <details open>.

Embedding media

For common providers like YouTube, Vimeo, and Spotify, the embed syntax is simpler — just embed: URL on its own line. Use inline HTML when you need full control over iframe attributes.

Embed videos, iframes, or any external content:

<video controls width="100%">
  <source src="/theme/videos/demo.mp4" type="video/mp4">
</video>

<iframe src="https://www.youtube.com/embed/VIDEO_ID"
  width="100%" height="400" frameborder="0"
  allow="accelerometer; autoplay; clipboard-write; encrypted-media"
  allowfullscreen></iframe>

Styling with theme variables

Inline styles can reference sitemd's CSS custom properties for consistent theming across light, dark, and paper modes:

<div style="color: var(--accent); border: 1px solid var(--border); padding: 1rem; border-radius: 8px;">
  This box adapts to the current theme mode automatically.
</div>

Commonly used variables:

Variable What it is
--accent Theme accent color
--text Primary text color
--text-secondary Muted text color
--bg Page background
--bg-secondary Subtle background (cards, callouts)
--border Border color

Mixing HTML and markdown

Markdown inside block-level HTML works if you leave blank lines between the HTML tags and the markdown content:

<div class="two-column" style="display: grid; grid-template-columns: 1fr 1fr; gap: 2rem;">
<div>

**Left column** with markdown content, lists, and [links](/).

</div>
<div>

**Right column** with completely different content.

</div>
</div>

Without the blank lines, the content inside the tags is treated as raw HTML and markdown syntax won't be processed.

Scripts

Inline <script> tags work the same as any other HTML — they execute when the page renders.

<div id="counter">0</div>

<script>
(function() {
  var el = document.getElementById('counter');
  var count = 0;
  el.addEventListener('click', function() {
    count++;
    el.textContent = count;
  });
})();
</script>

SPA navigation vs. full page loads

sitemd uses SPA-style navigation for internal links — clicking a link swaps the page content without a full reload. Inline scripts in the new page are re-executed after the swap.

On a full page load (direct URL, refresh, or external link), window.__sitemdAuth exists (auth.js loads in the <head>), but auth initialization is async — session recovery and magic link callbacks may still be in progress.

To safely depend on the auth API, wait for auth.ready:

(function() {
  function init() {
    var auth = window.__sitemdAuth;
    // auth is guaranteed to be available here
  }
  if (window.__sitemdAuth) window.__sitemdAuth.ready.then(init);
  else document.addEventListener('sitemd:auth-ready', init);
})();

This pattern works in both cases — on SPA navigation auth.ready is already resolved and init() runs on the next microtick; on a full page load it waits for initialization to complete.

Notes