Skip to content

Images and files

Where images go, how to reference them so they survive the build, Frame, theme variants, and non-image files.

This page covers the mechanics: where to put images, the one reference form that works, and what happens to files that are not images. For when to use a screenshot, how to size it and how to keep it current, see How to use images, screenshots and videos.

Reed copies your content directory into an Astro project it generates, then builds that project. The output is not a byte-for-byte copy of your content directory. Two things follow from that:

  • An image reaches the output only when a page references it with a relative markdown image. The build processes it and writes it to _astro/ under a hashed name. It may also convert it: a PNG can come out as .webp. SVG files keep their format.
  • Any other file in the content directory is not published. A PDF, CSV or video next to your pages does not appear in the output, even if a page links to it.

Put the image inside your content directory, near the page that uses it:

text
content/
guides/
webhooks.mdx
images/
webhook-settings.png

Reference it with markdown image syntax and a path relative to the page file:

mdx
![The webhook settings page with the signing secret field highlighted](./images/webhook-settings.png)

The rendered <img> gets the processed file’s URL, its intrinsic width and height, and lazy loading. Because the file name changes at build time, never link to an image by its original name from anywhere else.

Two forms compile without an error and ship a broken image:

  • A root-relative path. /docs/guides/images/webhook-settings.png is emitted as written, and no file exists at that URL. Reed does not serve the content directory at the site root.
  • An <img> tag with a local path. <img src="./images/webhook-settings.png" /> is not processed. The relative src is emitted unchanged, and the file is not in the output.

Use <img> only for images hosted at an absolute https:// URL. It is useful there because it accepts attributes markdown cannot, such as width:

mdx
<img src="https://cdn.example.com/architecture.png" alt="Requests flow from the edge through the API to the queue" width="600" />

JSX rules apply: close the tag with />.

Wrap the image syntax in a link:

mdx
[![The dashboard's usage chart for the last 30 days](./images/usage-chart.png)](https://dashboard.example.com/usage)

Every image needs non-empty alt text. A markdown image with empty brackets, an <img> without alt, and an <img> with alt="" all raise DS-A01, which is an error and fails the build. There is no way to mark an image as decorative. If an image carries no information, remove it.

The check only confirms that alt text exists. Whether it describes the image is up to you. The media guide and How to create accessible documentation cover writing it.

Frame puts an image in a bordered surface, with an optional hint above it and a caption below it. The caption accepts inline markdown such as emphasis and links. Props are in Layout and surfaces.

Put the markdown image directly inside the Frame. Write it on its own line with blank lines around it, or inline as <Frame>![alt](./x.png)</Frame>:

mdx
<Frame caption="Signing secrets are shown once. Copy yours before closing the dialog.">
![The new signing secret dialog with the Copy button](./images/signing-secret.png)
</Frame>

It no longer needs a <div> around it. The image must be the paragraph’s only content: an image followed by a sentence in the same paragraph does not count as the child. An empty Frame fails the page with DS-S02.

For an image at an absolute URL, an <img> is the child:

mdx
<Frame caption="The request lifecycle.">
<img src="https://cdn.example.com/lifecycle.png" alt="A request passing through auth, rate limiting and the handler" />
</Frame>

The caption is visible to everyone. It adds to the alt text; it does not replace it.

Reed has no image prop or syntax for theme variants. What works is the utility classes Starlight includes in every Reed build: dark:sl-hidden hides an element in the dark theme, and light:sl-hidden hides it in the light theme.

Markdown images cannot take a class, so wrap each variant in a <div>:

mdx
<div className="dark:sl-hidden">
![The API keys table](./images/api-keys-light.png)
</div>
<div className="light:sl-hidden">
![The API keys table](./images/api-keys-dark.png)
</div>

On an <img> with an absolute URL, put the class on the tag itself. Either className or class works: MDX parses the tag as JSX, and the output maps className to class.

Both images are in the page’s markup, and CSS displays one of them. Give both the same alt text. These classes come from Starlight rather than from Reed’s own component catalog, so check the rendered page after upgrading Reed.

Reed does not publish PDFs, archives, data files or other downloads from your content directory. A relative link such as [Download the guide](./files/guide.pdf) builds without an error, is emitted as written, and 404s, because the file is not in the output.

Host downloads somewhere built for them, such as your product’s CDN, object storage or a release page, and link to them by absolute URL:

mdx
[Download the integration guide (PDF, 2 MB)](https://downloads.example.com/integration-guide.pdf)

Say the format and size in the link text, so the reader knows what the click does.

Reed has no video component. Host the video on a platform built for it and link to it, with a sentence saying what it covers and how long it runs.

An <iframe> or <video> with an absolute src is emitted into the page as written. Reed does not check or style it. Write it as JSX, with camelCase attributes such as allowFullScreen, and give an iframe a title so a screen reader can announce it:

mdx
<iframe
src="https://www.youtube.com/embed/VIDEO_ID"
title="Setting up webhooks, a four-minute walkthrough"
width="560"
height="315"
allowFullScreen
></iframe>

A local video file is not published, for the same reason as a PDF. Review the built page before you rely on an embed, and put the information the reader needs in the page text too.

Your site’s logo and favicon are not content. They are set in docs.json, with paths relative to the directory docs.json is in, and reed check confirms the files exist. See Logo, favicon and custom CSS.