Skip to content
HomePagesHomePages template kit

Add a static asset

Add a graphic — an icon, a divider, a photo, a font — to a section.

Add a graphic — an icon, a divider mark, a photo, a custom font — to a section.

  • A section to hold the graphic — Install scaffolds one, with Renderer.tsx alongside section.ts and fixtures.ts.
  • A folder inside it for the file — assets/ for a binary, components/ for an inlined SVG — Organize a section’s files adds one.

A binary asset — an image, a font, a video, an archive — may live in a section’s own sections/<section>/assets/ folder, but only if the section references it: imported in Renderer.tsx (import crest from "./assets/crest.svg") or url()-referenced from one of the section’s CSS files. An unreferenced binary in the folder is flagged; see bundle-binary-asset for the rule and why.

A file shared across sections — a logo, a brand webfont, a texture — lives at the template level instead, referenced the same way with a ../../assets/… path. See Static assets for both paths and the full reference contract. What you reach for depends on what the graphic is:

A vector graphic — an icon, a divider, a decorative mark used only here. Inline it as SVG markup directly in the JSX that draws it. It is text, ships with the rest of your component, and needs no file or import at all:

sections/hero/components/ScrollArrow.tsx
export function ScrollArrow() {
return (
<svg viewBox="0 0 16 16" className="h-4 w-4" fill="none" aria-hidden="true">
<path d="M8 3v10M3 9l5 4 5-4" stroke="currentColor" strokeWidth="1.5" />
</svg>
);
}

Import it into the renderer — import { ScrollArrow } from "./components/ScrollArrow";, beside the imports that file already carries — then render it:

sections/hero/Renderer.tsx
<ScrollArrow />

That markup’s bytes ship inside the section’s renderer bundle, so they count toward the same byte budget as the rest of your JSX — see the size stage in Run check.

A raster image or watermark used only in this section. Add it under sections/<section>/assets/ and import it into the component:

sections/hero/Renderer.tsx
import crest from "./assets/crest.svg";
export default function Renderer() {
return <img src={crest} alt="" className="h-8 w-auto" />;
}

Or reference it from the section’s CSS with url() instead of importing it — see Static assets for both forms. Either way the file must be referenced: an asset nothing imports or url()-references is flagged by bundle-binary-asset.

A photo. Not a section asset at all — a section never ships a photo file. A photo arrives at runtime through an image slot: declare it with image() in section.ts, fill it with imageAssign() as that slot’s own fill:, and render it through Slot.Image, which owns the marker and reads url, alt, responsive and mobile off the binding. (The bare Image primitive is for the other direction — a template asset, which has no slot to bind to.) See Crop an image slot for the full shape.

A document — a brochure, a disclosure pack. Also not a section asset, and for the same reason: it belongs to the property rather than to the template. Declare a document slot and render it with Slot.Document — see Document slots. A .pdf in a section’s assets/ folder is only ever a file the template itself ships on every deliverable.

A custom font shared across the template. Declared once, for the whole template, as a fonts entry in the theme, with the font files themselves in the template’s own fonts/ folder — see Loading a web font, the route a rendered template has no alternative to. A font only one section uses can instead live in that section’s assets/ folder and be declared with a @font-face in the section’s own CSS — see Static assets.

The fences under Steps are the whole change: SVG markup inlined in a component, plus the import that pulls that component into Renderer.tsx and the line that renders it — or a file under the section’s assets/ folder plus the import that references it.

Verify with the author loop.

  • bundle-binary-asset — the file lands in the section folder but nothing imports or url()-references it.
  • size-assets — one static asset is heavier than the guideline. A warning only; it never fails the check.
  • size-renderer-bundle — a large inlined SVG ships inside the renderer bundle and pushes it past its byte budget.
  • Static assets — the full reference/import contract, template level vs. section folder.
  • bundle-binary-asset — the rule that flags an unreferenced binary in a section folder, and the SVG-inlining fix.
  • Run check — the size stage a large inlined SVG or a bloated renderer bundle counts against.
  • Crop an image slot — the real channel for a photo: an image slot, an imageAssign decision, and Slot.Image.
  • TokenTheme — where a template’s fonts are declared.