Shortcodes

Shortcodes let you embed rich, reusable components inside markdown without writing raw HTML. They use square-bracket notation and are expanded before the markdown parser runs.

Inline Shortcodes

Self-closing shortcodes produce output without a body:

[figure src="/img/photo.jpg" alt="A photo" caption="My photo"/]

Renders as:

<figure><img src="/img/photo.jpg" alt="A photo"><figcaption>My photo</figcaption></figure>

Block Shortcodes

Block shortcodes wrap body content between opening and closing tags:

[infobox type="info"]
This is an **informational** message with _markdown_ inside.
[/infobox]

Renders as:

<div class="infobox infobox-info" role="complementary" aria-label="Info">
<p class="infobox-title">Info</p>
This is an <strong>informational</strong> message with <em>markdown</em> inside.
</div>

Attribute Syntax

Shortcodes support positional arguments, named key-value pairs, and flags:

[button primary href="/signup"]Get Started[/button]
[youtube id="dQw4w9WgXcQ" autoplay/]
[details summary="Click to expand"]Hidden content[/details]
SyntaxDescription
primaryPositional argument (bare word)
href="/signup"Named argument (key-value)
autoplayFlag (bare word, treated as boolean)

Named values must be quoted when they contain spaces. Single or double quotes are accepted.

Built-in Shortcodes

Accent CMS ships with these built-in shortcodes:

ShortcodeUsageDescription
button[button primary href="/signup"]Label[/button]Anchor link styled as a button
infobox[infobox type="prereq" title="Setup"]...[/infobox]Rich content box with type, title, and optional collapsibility
tabs[tabs group="os"][tab label="macOS"]...[/tab][/tabs]Tabbed content switcher with group sync
details[details summary="Title"]Content[/details]Collapsible disclosure element
figure[figure src="/img/x.jpg" alt="desc" caption="Cap"/]Figure with image and optional caption
iframe[iframe src="demo.html" title="Demo"/]Embed a page-local or external HTML page
pdf[pdf src="report.pdf" title="Q4 Report"/] PDF download card with thumbnail preview, title, and download link. Falls back to a generic SVG icon when no thumbnail is available
diagram[diagram type="mermaid"]flowchart LR; A --> B[/diagram]Server-render a Mermaid or Svgbob diagram with caption, alt text, and external src support. See the Diagrams guide for the full attribute table, render-mode policy, and an agent-authoring cookbook.

The [alert] shortcode name is supported as a deprecated alias for [infobox]. Existing content using [alert warning]...[/alert] continues to work.

Iframe Shortcode

The iframe shortcode embeds standalone HTML pages or external URLs in an isolated iframe. This is useful for design system demos, interactive widgets, or third-party content that has its own styles and scripts.

Embed a page-local HTML file:

[iframe src="accent-design.html" title="Design System"/]

When src is a relative path (not starting with http://, https://, or //), it is resolved through the /content-media/ route relative to the current page. For a page at /designsystem, this produces src="/content-media/designsystem/accent-design.html". Place the HTML file in the same content directory as your markdown page.

Embed an external URL:

[iframe src="https://example.com/demo" title="Live Demo" height="800"/]

External URLs pass through unchanged.

Available attributes:

AttributeDefaultDescription
src(required)URL or page-local filename to embed
title(required)Accessible title for the iframe
height600Height as a CSS value
width100%Width as a CSS value
border0CSS border value
loadinglazylazy or eager loading
sandbox(omitted)Sandbox restrictions (e.g., allow-scripts)
allow(omitted)Permissions policy (e.g., fullscreen)

Themes can override the built-in iframe by providing shortcodes/iframe.html.jinja in the theme directory.

Embedded HTML and the media CSP

Files served through /content-media/ carry a strict Content-Security-Policy by default (default-src 'none'; sandbox). That is the right policy for images and downloads, but for an embedded HTML page it blocks every subresource – inline <style> blocks, images, fonts, and scripts – so the iframe renders as bare unstyled HTML with no error anywhere.

To make an embedded page work, add a scoped override in config.yaml for exactly the path that needs it:

http_headers:
  security:
    routes:
      - path: "/content-media/designsystem/*"
        content_security_policy: "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'"

This permits same-origin resources and inline styles for that one page’s media directory while every other /content-media/ response keeps the strict default. If the embedded page needs scripts or external origins, extend the policy for that route only, for example script-src 'self' 'unsafe-inline' or style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com.

Keep overrides as narrow as possible: anything that can upload HTML into a covered content directory (for example the admin media library) is granted the same relaxation. See the configuration reference for matching and precedence details.

Theme Shortcodes

Themes can override built-in shortcodes or define new ones by placing Jinja templates in the shortcodes/ directory:

site/themes/default/shortcodes/
    button.html.jinja
    alert.html.jinja
    custom-widget.html.jinja

Theme shortcode templates receive these context variables:

  • args.positional – list of positional arguments
  • args.named – dictionary of named arguments
  • body – the body content (empty string for self-closing shortcodes)

Example theme shortcode template (shortcodes/badge.html.jinja):

{% set variant = args.positional[0] | default("info") %}
<span class="badge badge-{{ variant }}">{{ body }}</span>

Used as: [badge success]Done[/badge]

Plugin Shortcodes

Plugins can also register shortcodes via the [shortcodes] section in plugin.toml. See the Plugins documentation for details.

Resolution Order

When a shortcode is encountered, Accent CMS resolves it through this chain:

  1. Built-in shortcodes (always available)
  2. Theme shortcodes (Jinja templates in shortcodes/)
  3. Plugin shortcodes (registered by WASM plugins)

The first resolver that handles the shortcode wins. This means themes can override built-in shortcodes, and plugins can add entirely new ones.

Unrecognized shortcodes are passed through unchanged so they appear as literal text in the output.