Private betav0.1.0
Docs
Format developer documentation

Images

How to use images in Format Studio documents.

Referencing assets

There are two ways to load bitmap images, like jpg and png.

As a module import

As you might be used to in your existing React or Vue projects, you can import an asset as an ES Module, using an import statement.

documents
invoice
styles.css
index.tsx
banner.jpg
documents/invoice/index.tsx
import { Document, Layout } from '@format.dev/react'
import banner from './banner.jpg'

export default function Invoice() {
	return (
		<Document title="Invoice">
			<Layout id="invoice" width={793.71} height={1122.52}>
				<img src={banner} alt='Banner' />
			</Layout>
		</Document>
	)
}
documents
invoice
styles.css
index.vue
banner.jpg
documents/invoice/index.vue
<script setup lang="ts">
import { Document, Layout } from '@format.dev/vue'
import banner from './banner.jpg'
</script>

<template>
	<Document title="Invoice">
		<Layout id="invoice" :width="793.71" :height="1122.52">
			<img :src="banner" alt="Banner" />
		</Layout>
	</Document>
</template>

From an assets directory

You can put assets in one of two places:

  • A special directory called assets nested under each document
  • A user-defined sharedAssetsDir that all documents can see
shared-assets
logo.png
documents
invoice
assets
banner.jpg
index.tsx
styles.css
format.config.json
format.config.json
{
	"sharedAssetsDir": "./shared-assets"
}
documents/invoice/index.tsx
import { Document, Layout } from '@format.dev/react'

export default function Invoice() {
	return (
		<Document title="Invoice">
			<Layout id="invoice" width={793.71} height={1122.52}>
				<img src='./banner.jpg' alt='Banner' />
				<img src='./logo.png' alt='Acme logo' />
			</Layout>
		</Document>
	)
}
shared-assets
logo.png
documents
invoice
assets
banner.jpg
index.vue
styles.css
format.config.json
format.config.json
{
	"sharedAssetsDir": "./shared-assets"
}
documents/invoice/index.vue
<script setup lang="ts">
import { Document, Layout } from '@format.dev/vue'
</script>

<template>
	<Document title="Invoice">
		<Layout id="invoice" :width="793.71" :height="1122.52">
			<img src='./banner.jpg' alt='Banner' />
			<img src='./logo.png' alt='Acme logo' />
		</Layout>
	</Document>
</template>
shared-assets
logo.png
documents
invoice
assets
banner.jpg
index.html
index.ts
styles.css
format.config.json
format.config.json
{
	"sharedAssetsDir": "./shared-assets"
}
documents/invoice/index.html
<template data-type="document" data-title="Invoice">
	<template data-type="layout" data-id="invoice" data-width="793.71px" data-height="1122.52px">
		<img src="./banner.jpg" alt="Banner" />
		<img src="./logo.png" alt="Acme logo" />
	</template>
</template>

If there is a filename clash between these two, the document's assets directory wins.

You can use any directory structure inside an assets folder to organize assets.

shared-assets
brand
latest
logo.png
documents
invoice
assets
layout
v1
banner.jpg
index.tsx
styles.css
format.config.json
documents/invoice/index.tsx
import { Document, Layout } from '@format.dev/react'

export default function Invoice() {
	return (
		<Document title="Invoice">
			<Layout id="invoice" width={793.71} height={1122.52}>
				<img src='./layout/v1/banner.jpg' alt='Banner' />
				<img src='./brand/latest/logo.png' alt='Acme logo' />
			</Layout>
		</Document>
	)
}
shared-assets
brand
latest
logo.png
documents
invoice
assets
layout
v1
banner.jpg
index.vue
styles.css
format.config.json
documents/invoice/index.vue
<script setup lang="ts">
import { Document, Layout } from '@format.dev/vue'
</script>

<template>
	<Document title="Invoice">
		<Layout id="invoice" :width="793.71" :height="1122.52">
			<img src='./layout/v1/banner.jpg' alt='Banner' />
			<img src='./brand/latest/logo.png' alt='Acme logo' />
		</Layout>
	</Document>
</template>
shared-assets
brand
latest
logo.png
documents
invoice
assets
layout
v1
banner.jpg
index.html
index.ts
styles.css
format.config.json
documents/invoice/index.html
<template data-type="document" data-title="Invoice">
	<template data-type="layout" data-id="invoice" data-width="793.71px" data-height="1122.52px">
		<img src="./layout/v1/banner.jpg" alt="Banner" />
		<img src="./brand/latest/logo.png" alt="Acme logo" />
	</template>
</template>

SVGs

Building on the above, you can load SVGs in three ways, each with different trade-offs.

As an image

Reference an SVG from an assets directory using an <img> tag. The SVG is treated as a static image. You cannot style fill, stroke, or other SVG properties via CSS from outside the element. It is still rendered as a scalable vector.

documents
invoice
assets
logo.svg
styles.css
index.tsx
<img src='./logo.svg' alt='Acme logo' />
<img src='./logo.svg' alt='Acme logo' />
<img src="./logo.svg" alt="Acme logo" />

As a component

Import the .svg file as a module to use it as an inline component. The SVG markup is rendered directly into the HTML output, giving you full access to style fill, stroke, and other SVG properties via CSS.

Studio uses vite-plugin-svgr to transform SVG imports into React components.

documents/invoice/index.tsx
import { Document, Layout } from '@format.dev/react'
import Logo from './assets/logo.svg'

export default function Invoice() {
	return (
		<Document title="Invoice">
			<Layout id="invoice" width={793.71} height={1122.52}>
				<Logo />
			</Layout>
		</Document>
	)
}

Studio uses vite-svg-loader to transform SVG imports into Vue components.

documents/invoice/index.vue
<script setup lang="ts">
import { Document, Layout } from '@format.dev/vue'
import Logo from './assets/logo.svg'
</script>

<template>
	<Document title="Invoice">
		<Layout id="invoice" :width="793.71" :height="1122.52">
			<Logo />
		</Layout>
	</Document>
</template>

Inline

Paste SVG markup directly into your template. This gives you the same benefits as the component approach, without needing a separate file.

documents/invoice/index.tsx
import { Document, Layout } from '@format.dev/react'

export default function Invoice() {
	return (
		<Document title="Invoice">
			<Layout id="invoice" width={793.71} height={1122.52}>
				<svg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>
					<circle cx='12' cy='12' r='10' fill='#FF5A06' />
				</svg>
			</Layout>
		</Document>
	)
}
documents/invoice/index.vue
<script setup lang="ts">
import { Document, Layout } from '@format.dev/vue'
</script>

<template>
	<Document title="Invoice">
		<Layout id="invoice" :width="793.71" :height="1122.52">
			<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
				<circle cx="12" cy="12" r="10" fill="#FF5A06" />
			</svg>
		</Layout>
	</Document>
</template>
documents/invoice/index.html
<template data-type="document" data-title="Invoice">
	<template data-type="layout" data-id="invoice" data-width="793.71px" data-height="1122.52px">
		<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
			<circle cx="12" cy="12" r="10" fill="#FF5A06" />
		</svg>
	</template>
</template>

Assets based on variable data

When you need to load a different assets based on the dynamic data within your document, you have a few choices:

<img src={data.theme === 'dark' ? 'logo-dark.png' : 'logo-light.png'} />

Which is perfectly acceptable, but does assume that assuming that both logo-dark.png and logo-light.png are in one of your document asset directories. Both files would be zipped and be available at render time.

If, for example you were to load a variant where data.theme was set to dark in Studio and you didn't have logo-dark.png available, Studio will show a warning diagnostic, making it hard to miss.

However, in the case that don't have a variant that triggers logo-dark.png to be loaded, and logo-dark.png isn't present (and thus not zipped when you compile for production), you would get an AssetMismatchError at runtime. Still not catastrophic, as you can handle this error appropriately, but it's worth being aware of.

You could also use a module import, which would flag the issue much earlier:

import logoLight from './logo-light.png'
import logoDark from './logo-dark.png'

<img src={data.theme === 'dark' ? {logoDark} : logoLight} />

If you need to use assets that are completely dynamic at runtime, for example user uploaded images, you should use Dynamic mode when running compile.

Was this page helpful?