# Template Shortcodes URL: /docs/extending/shortcodes/ Section: extending -------------------------------------------------------------------------------- Shortcodes are template-based content components you can add without writing Python. Place a Kida template in templates/shortcodes/ and call it from Markdown using Hugo-compatible syntax. When to Use Shortcodes vs Directives Criterion Shortcode (template) Directive (Python) Implementation Kida template file Python class Location templates/shortcodes/name.html bengal/.../directives/builtins/ Validation Template conditionals only Regex, typed options Who can add Content/template authors Developers Choose a shortcode when: Output is simple HTML from args (styled blockquote, custom figure) No strict validation needed (e.g., "any URL" iframe) You want non-developers to add or customize it You want to override without touching code Choose a directive when: You need validation (YouTube 11-char ID, Spotify 22-char ID) You need computed URLs, privacy mode, or complex options You need parent-child nesting (e.g., :::{step} inside :::{steps}) You want structured errors and build-time safety See Custom Directives for the Python path. Notation: Markdown vs Standard Shortcodes support two notations that control how inner content is processed: Notation Example Inner content Standard {{ }}...{{ }} Passed raw to template Markdown {{ % name args % }}...{{ % /name % }} Parsed as Markdown first Use Markdown notation when inner content should support formatting (e.g. **bold**, [links](url)): <blockquote class="blockquote">&lt;p&gt;The only way to do great work is to &lt;strong&gt;love&lt;/strong&gt; what you do.&lt;/p&gt; <footer>— Jane</footer> </blockquote> Use standard notation when inner content should stay as-is (e.g. raw HTML or code): <pre><code class="language-python"> def hello(): print(&quot;world&quot;) </code></pre> Creating a Shortcode Create a template at templates/shortcodes/<name>.html Use it in content with {{ }} or {{ }}content{{ }} Self-Closing Shortcodes For shortcodes without inner content: {# templates/shortcodes/audio.html #} {% set src = shortcode.Get("src") %} {% if src %}<audio controls preload="auto" src="{{ src }}"></audio>{% end %} In content: <audio controls preload="auto" src="/audio/test.mp3"></audio> Paired Shortcodes For shortcodes with inner content: {# templates/shortcodes/blockquote.html #} <blockquote class="blockquote"> {{- shortcode.Inner -}} {% set author = shortcode.Get("author") %} {% if author %}<footer>— {{ author }}</footer>{% end %} </blockquote> In content (use {{ % % }} for Markdown in inner content): <blockquote class="blockquote">&lt;p&gt;The only way to do great work is to &lt;strong&gt;love&lt;/strong&gt; what you do.&lt;/p&gt; <footer>— Jane Doe</footer> </blockquote> Shortcode Context Templates receive a shortcode object with Hugo-compatible methods: Property Description shortcode.Get("key") Get named argument shortcode.Get(0) Get positional argument (0-indexed) shortcode.GetInt("key", 0) Get argument as int shortcode.GetBool("key", false) Get argument as bool (true/false, 1/0) shortcode.Inner Inner content (paired shortcodes only) shortcode.InnerDeindent Inner with leading indentation stripped shortcode.IsNamedParams True if named args were used shortcode.Params All params as dict or list shortcode.Ref("path") Resolve content path to absolute URL shortcode.RelRef("path") Resolve content path to relative URL shortcode.Parent Parent shortcode context when nested (or None) You also have page, site, and config in context. Use page.HasShortcode("name") in layouts to check if a page uses a given shortcode (e.g. to conditionally load CSS). Arguments Named arguments: <figure class="figure"> <img src="/images/cat.jpg" alt="A cat" loading="lazy"> <figcaption>Photo by Jane</figcaption> </figure> Positional arguments: Arguments with spaces must be quoted: <blockquote class="blockquote">Quote <footer>— Jane Doe</footer> </blockquote> Subdirectory Shortcodes Organize shortcodes in subdirectories: templates/shortcodes/ ├── media/ │ ├── audio.html │ └── video.html └── blockquote.html Call with the path relative to shortcodes/: {{< media/audio src=/audio/test.mp3 >}} Built-in Shortcodes The default theme ships with these shortcodes. Override any by placing a template with the same name in your project's templates/shortcodes/. Shortcode Usage Purpose audio ` | HTML5 audio player | |blockquote| <p>Quote</p> — Name ` | Styled blockquote with attribution | | `figure` | ` <img src="/img.jpg" alt="..." loading="lazy"> <figcaption>...</figcaption> | Image with optional caption and link | |details| Click <p>Content</p> ` | Collapsible `` | | `highlight` | ` code | Code block with language class | |param| | Insert config or frontmatter value | |tip| Tip <p>Hint</p> ` | Tip callout box | | `warning` | ` Warning <p>Caution</p> ` | Warning callout box | | `danger` | ` Danger <p>Critical</p> ` | Danger callout box | | `ref` | ` docs/guide/intro | Internal page link (absolute URL) | |relref| docs/guide/intro ` | Internal page link (relative URL) | Strict Mode Set shortcodes.strict: true in bengal.yaml to fail the build when: An unknown shortcode is used (no template found) A shortcode template fails to render Useful for CI and catching typos early. Discoverability List available shortcodes: bengal shortcodes list Shortcode Cookbook Copy-paste snippets for common patterns. Conditional CSS in base layout {% if page.HasShortcode("audio") %} <link rel="stylesheet" href="/css/audio-player.css"> {% end %} Nested shortcode with parent {# templates/shortcodes/img.html — used inside gallery #} {% set cls = shortcode.Parent.Get("class") if shortcode.Parent else "" %} <img src="{{ shortcode.Get('src') }}"{% if cls %} class="{{ cls }}"{% end %}> Internal link with custom text Typed arguments {% set cols = shortcode.GetInt("cols", 3) %} <div class="grid grid-cols-{{ cols }}"> {{ shortcode.Inner }} </div> Related Custom Directives — Python-based directives with validation Theme Customization — Override templates Kida Syntax — Template language reference -------------------------------------------------------------------------------- Metadata: - Author: lbliii - Word Count: 790 - Reading Time: 4 minutes