Inline modes
inline ref vs inline svg — when to store the URL reference vs the actual SVG markup directly in frontmatter.
A storage's inline: knob controls what shape the frontmatter value
takes when an author picks or uploads a file. Two values ship:
inline: ref(default) — the value is the public URL or repo-rooted path, exactly as described in Frontmatter shape. Your template renders<img src={frontmatter.icon} />(or imports the file for build-imported assets).inline: svg— the value is the SVG markup string itself, dropped directly into frontmatter. Your template renders{@html frontmatter.icon}(or framework equivalent) with no import plumbing.
This page covers both — when to pick each, what the editor does, and what the trade-offs are.
inline: ref (default)
The vanilla case. The value is a URL; the consuming template renders an
<img> tag (or invokes its build-time importer for no-publicUrl
storages).
storages:
uploads:
type: repo
path: public/uploads
publicUrl: /uploads
inline: ref # default; same as omittingPicking hero.jpg writes /uploads/hero.jpg to frontmatter. Standard
flow; no surprises. Use inline: ref for:
- Photos, screenshots, hero images — anything where
<img>is the right semantic. - File downloads (PDFs, videos, audio) — never inlinable into text.
- Most SVGs that aren't being used as icons (illustrations, decorative graphics that don't need to be styled per-instance).
This is what every other CMS does. The inline: knob defaults here for
that reason.
inline: svg
For icon libraries where you want the SVG markup live in your template,
not behind an <img src=…>. The frontmatter value becomes the full SVG
string:
storages:
icons:
type: repo
path: src/assets/icons
inline: svg
mode: read-only # icons added via PR, picker is read-onlyPicking check.svg writes:
icon: |
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M20 6L9 17l-5-5"/>
</svg>The consuming template uses raw-HTML rendering:
<!-- SvelteKit -->
{@html frontmatter.icon}<!-- Astro -->
<Fragment set:html={frontmatter.icon} />{
/* React */
}
<span dangerouslySetInnerHTML={{ __html: frontmatter.icon }} />;Why use it
The killer feature: the inline SVG inherits CSS from its parent.
<button class="text-violet-600 hover:text-violet-700">
{@html frontmatter.icon} Save
</button>The icon picks up text-violet-600 via fill="currentColor" /
stroke="currentColor" in the SVG. With <img> you'd have to either:
- Bake the colour into the SVG file (loses per-instance styling).
- Use SVG sprites +
<use href>(extra build step + a<svg>wrapper per icon). - Use an SVG-as-component build plugin (heavyweight per-framework).
inline: svg gets you native CSS styling, zero plumbing.
The other win is zero build dependencies. No SVGO loader, no Vite plugin, no Astro integration — your template just renders a string. Works the same on every framework.
Editor behaviour
When a field references an inline: svg storage:
On pick: the picker hands back the file's public URL as normal,
then the editor sniffs the storage's inline: mode. For svg, it
fetches the file's bytes via the signed-URL flow (POST /v1/sites/:id/media/sign + GET the signed URL) and writes the markup
string to the field instead of the URL.
On drag-drop: the file gets uploaded to git as normal (so other
inline-svg fields can pick the same icon later), AND the editor reads
the original File client-side as text (no extra network round-trip)
and writes that to the field.
On read: the editor detects inline values via value.trim(). startsWith('<svg'). When detected:
- The display chip's URL pill flips to a violet "inline svg" badge.
- The path display shows
"… chars of SVG"instead of trying to truncate XML. - The preview area renders
{@html displayValue}(matches what the deployed site will render).
What the bytes still live in git
inline: svg doesn't replace the upload — it augments it. When
an author uploads an SVG to an inline-svg storage:
- The bytes get committed to git at the storage's
pathas usual. - The bytes ALSO get inlined into the field's frontmatter as the markup string.
This means future picker selections (on other pages, other fields) can still pick the same icon from the library — the picker reads from git. Each pick that happens through an inline-svg storage inlines the bytes into its own frontmatter; the git copy is the library, the inlines are instances.
The trade-off — duplication
Every page that uses an inline icon carries its own copy of the markup in its YAML:
# pages/about.md
icon: |
<svg viewBox="0 0 24 24"><path d="..."/></svg>
# pages/contact.md
icon: |
<svg viewBox="0 0 24 24"><path d="..."/></svg>
# pages/team.md
icon: |
<svg viewBox="0 0 24 24"><path d="..."/></svg>For a 5-line SVG times 50 pages, that's 250 extra lines across your content tree. Git diffs are noisier (changing an icon means N file changes), and your build's content payload is bigger.
Compare to inline: ref:
# pages/about.md
icon: /src/assets/icons/check.svg
# pages/contact.md
icon: /src/assets/icons/check.svgOne source of truth on disk, references everywhere. The build pulls the file once (and a smart bundler de-dupes); only one place to change the icon.
When to pick which
Pick inline: svg when:
- The icons are styled per-instance via parent CSS (text colour,
size). The CSS inheritance through
currentColoris the win. - The site is small (< 50 pages) — the duplication cost is negligible.
- You don't want any framework-specific build plumbing for icon rendering.
- The icon library is small and stable — changes are rare so the re-publish-N-pages cost rarely comes up.
Pick inline: ref (default) when:
- The site is large. Every duplication costs.
- The icons are decorative (no per-instance styling).
<img>is fine; no need to inline. - You already have a build-time SVG pipeline (Vite plugin, Astro's Image component, etc).
- The icon library is large or changes often — single-source-of- truth + diff hygiene beats zero-plumbing rendering.
Editor restriction: read-only storages
Inline-svg storages typically live alongside mode: read-only —
icons are an asset library maintained outside the CMS (designer PRs).
The picker still scopes to the storage and inlines on pick; only the
upload affordance is hidden.
You CAN have a read-write inline-svg storage if you want authors to upload icons through the CMS. Less common; the inline duplication makes more sense for curated libraries.
Future inline modes
The shape of inline: is a discriminated union — ref / svg
today, room for html / json / markdown later. The validator
will reject unknown values until each lands, so a typo
(inline: smg) fails at config-load.
If we ever ship inline: html (inline a static HTML snippet) or
inline: json (inline structured data), the editor's detection
heuristic generalises — sniff the value's leading characters and
pick the rendering path.