Developers
Start building
Themes/Theme assets and media

Theme assets and media

Ship images, fonts and icons in a theme's assets/ folder and name them from code, settings and CSS. Covers the size caps, the store's media library (media://), the media/* rules of the theme check and the code editor's asset tools.

On this page

A theme draws two kinds of pictures, and they live in different places:

KindOwnerWhere it livesHow a theme names it
Theme assetsThe themeThe theme's assets/ folder, versioned with codeasset('images/hero.jpg') in code, asset://images/hero.jpg in settings
Store filesThe storeThe store's media library (Media library in the admin)media://<id> in settings a merchant fills; never in code

Assets travel with the theme: they are copied when the theme is duplicated, and installed with it. Store files belong to the store: a merchant uploads them once and uses them in every theme, product, email and page. Ship drawn pictures, patterns, icons and fonts as assets, and leave photos to the merchant. The shipped themes carry no photos.

The assets/ folder

Every binary file of a theme sits under assets/, in folders of your choice (assets/images/hero.svg, assets/fonts/display.woff2). A binary file anywhere else is refused, by the code editor, the CLI and theme install alike.

TypeExtensionsCap
Imagejpg, jpeg, png, webp, avif, gif5 MB a file; over 2 MB still installs, with a warning
Vectorsvg256 KB; sanitized on the way in
Fontwoff21 MB; other font formats are refused, convert to WOFF2
Iconico5 MB; over 2 MB still installs, with a warning
Themeeverything under assets/50 MB in total

Sizes are binary: 1 MB is 1024 × 1024 bytes.

  • A path is relative to assets/, at most 256 characters, with letters and digits of any script plus ., _ and - in each folder name; no leading dot, no spaces, and the file needs an extension.
  • The bytes are checked against the type: an image must decode as the type its extension names, a font and an icon must carry their file signature, and an SVG goes through the same sanitizer as the store's library (scripts, event handlers, external links and embedded rasters refuse the file).
  • Each asset is stored once per store, by its content, so two themes with the same file share it and a duplicated theme copies only the reference.

Example assets

Every shipped theme carries one or two small examples under assets/images/. Each one is used, so media/unused-asset stays quiet, and together they show the patterns:

  • backdrop.svg, a quiet still life in the theme's palette. It is the asset://images/backdrop.svg default of an image setting (the promo card of the default theme, the cover plate of Editorial, the feature image of Launch) and the value the home page starts with.
  • hatch.svg, a hairline tile that url(asset:images/hatch.svg) lays under an empty image plate in the default, Editorial and Essential themes.

The files are drawn from plain SVG shapes, so there is no third-party artwork to license. A theme whose code you changed before these files shipped did not receive them. Delete them if you do not want them.

In code: asset()

import { MediaImage, asset } from '@poltura/theme-sdk/media';

export function Hero() {
  return <MediaImage image={asset('images/hero.svg')} role='hero' alt='' />;
}
FunctionReturns
asset(path)The reference asset://<path>, for any prop that takes a picture (MediaImage). Throws on a malformed path
useAssetUrl(path, role?)A URL: the role's rendition of an image, or the whole file without a role (always for SVG, fonts and icons). Null when the asset is missing
useThemeAsset(path)The resolved file (url, width, height, hasAlpha) or null. An asset has no alt text of its own

Roles are the same as for library files: thumb, card, tile, pdp, zoom, hero, og, logo and icon. MediaImage draws an asset the way it draws a library file: a <picture> with AVIF and WebP where the role allows, srcset for high-density screens, and the stored width and height so the layout does not shift.

The theme build writes an asset manifest into every built version of the theme: each asset's path, hash, type, size, pixel size and URLs. A path missing from the manifest renders a placeholder, never a broken image, and the check reports it (below). Write the path as a literal where you can. An asset() call with a computed path is allowed, but it turns off the unused-asset report for the whole theme.

media:// never appears in code. A store's file is something a merchant chooses, so it comes in through a setting.

In settings and pages: asset://

Image settings, style backgrounds and every picture value of a page or layout JSON take a reference: media://<id> for a store file the merchant picked, asset://<path> for a theme asset.

import { field } from '@poltura/theme-sdk/elements';

const settings = {
  background: field.image({ label: 'Background', default: 'asset://patterns/dots.svg' }),
};

An image setting may default to an asset, and only to an asset. A media:// reference or an address as a default throws, because a theme cannot know a store's files and must not depend on another host. video settings take no default. In the Customizer a merchant replaces the default with a file of their library; the reference they pick is what the setting stores.

In CSS: url(asset:…)

src/styles/theme.css
.hero {
  background-image: url(asset:patterns/dots.svg);
}

The theme build rewrites url(asset:<path>) (quotes optional, asset:// accepted too) to the file's address on the store's /media/ path. A path that is not in assets/ fails the build with the error code THEME_ASSET_MISSING. Write url(asset:…) without the slashes, because that is the form the check reads.

The theme check: media/* rules

The CLI (poltura theme check), theme install and the code editor run the same rules. The severity differs only where one of them knows less or where more is at stake:

RuleCLI / install / code editorReports
media/no-remote-urlwarning / error / warningAn http(s) address in a picture value. A shipped theme cannot depend on another host
media/unsafe-urlerror everywherejavascript:, data: and similar in a picture or link value. An inline SVG data URL of up to 2048 characters is allowed in an <img> src
media/unresolvable-patherror everywhereA bare or rooted path nothing serves (/images/x.jpg, hero.jpg) or a malformed media:// / asset://
media/unknown-asseterror everywhereAn asset:// or asset('…') path with no file in assets/; suggests the nearest name
media/unknown-mediawarning (install and code editor)A media:// id that is not in this store's library
media/ref-in-codeerror everywheremedia:// inside src/
media/image-altwarning everywhereAn <img> of the theme's own without alt or decorative
media/asset-sizewarning over the budget, error over the capA file over its type's budget or cap, the 50 MB total, or a font that is not WOFF2
media/unused-assetinfo everywhereAn asset nothing names

The check's rule against placeholder addresses in text skips picture and link values. The media/* rules judge an address there instead.

In the code editor

  • The folder is always there. assets/, assets/images/ and assets/fonts/ show in the Explorer for every theme, including one with no asset yet, and stay when their last file is deleted or moved: they are folders of the workspace, not placeholder files, and nothing about them is stored with the theme.
  • Assets are files. Drop images, SVG, fonts and icons from your computer into assets/ in the Explorer. Renaming or moving a file updates every reference to it and saves the files it changed. A file the folder cannot hold (bytes outside assets/, over its cap, of another type) is refused with a notification that says why.
  • Previews. An image, font or icon under assets/ opens in a preview with its size, bytes and a Used in list. A font shows a specimen with sample text. Preview asset in the Explorer's context menu opens one, and an SVG file has a preview button in its editor title bar.
  • Media library. The Media library view (its own activity-bar icon) lists the store's files by kind, with search. Drag a file into a JSON file to insert its media:// reference, or run Pick from the media library there. Upload to library adds a file to the store's library. Upload videos on the admin's Media library page.
  • Completion and hints. Typing asset(', useAssetUrl(', useThemeAsset(', "asset:// or url(asset: lists the theme's assets, and "media:// lists the store's images. Hovering a reference shows the file, and its link opens the preview. Inlay hints show the pixel size, the library file's name and alt text, or that a reference points at nothing.
  • Problems and quick fixes. After every save the full theme check runs and fills Problems (source poltura-check), with fixes where the rule has one: Use asset://… for a path a file in assets/ matches, Did you mean asset://…?, Pick a file from the media library, Upload to the media library for a remote address, Add an image_alt setting and Remove this value.

Next

Last updated