RSTRust-First Site ToolkitA Rust-first static site generator with typed collections, explicit routes, and a format-agnostic asset pipeline.

Blog

Markdown Components Are Rust Functions

Markdown-generated tags can be replaced with Rust functions so links, images, and other authored content remain customizable without turning markdown into an opaque HTML string step.

Markdown does not have to be the end of customization

Many static site pipelines treat markdown as a one-way conversion into an HTML string.

That makes customization awkward. The moment you want:

  • custom links

  • responsive images

  • richer code blocks

  • route-aware components

you end up patching HTML after the fact or introducing a second template layer.

This project takes a different approach.

The public API surface

The relevant API pieces are:

  • SiteBuilder::markdown_component(...)

  • ComponentProps

  • ComponentProps::attr(...)

  • ComponentProps::asset_url(...)

  • ComponentProps::image_url(...)

  • ComponentProps::responsive_image(...)

  • ComponentProps::probe_image(...)

That gives markdown components a small, Rust-native interface instead of exposing the full markdown AST to ordinary site code.

Markdown-generated tags can be overridden

The site builder can replace one generated HTML tag with a Rust function:

.markdown_component("a", components::smart_link)
.markdown_component("img", components::responsive_image)

The component receives ComponentProps, which includes:

  • the generated tag name

  • the generated attributes

  • the rendered children

  • helper methods for resolving assets and image outputs

That keeps customization in ordinary Rust instead of in a separate macro or HTML-rewrite step.

Asset-aware components matter most for images

Image tags are where this becomes especially valuable.

A custom img component can:

  • preserve SVG inputs as vector output by default

  • request responsive AVIF outputs for raster images

  • probe the authored source when dimensions matter

And it can do all that through the same asset pipeline used by route handlers.

That means markdown-authored content can still benefit from:

  • deterministic asset URLs

  • transform caching

  • format-agnostic output requests

  • correct relative-path resolution

Why this is better than post-processing HTML

Post-processing HTML is often too late.

At that point you have already lost the meaningful structure:

  • which attributes mattered

  • where local asset resolution should happen

  • what source document the reference came from

The markdown component hook preserves those decisions at the right layer.

Where to go next