<GioImage>
An <img> served through the built-in image optimizer, with a srcset of the widths gio.toml allows, lazy loading, and a preload for the hero image.
import { GioImage } from '@gio.js/react';
export default function Home() {
// public/hero.jpg, served at /hero.jpg
return <GioImage src="/hero.jpg" alt="The harbor at dawn" width={1200} height={630} priority />;
}The Rust server resizes and re-encodes the image on its first request at /_gio/image (AVIF or WebP when the browser accepts them) and caches the result. GioImage builds the URLs; how the optimizer works is in Image Optimization.
Reference
| Prop | Type | Default | Description |
|---|---|---|---|
src (required) | string | - | A file in public/ (/hero.jpg or /public/hero.jpg), or a remote URL that [[images.remote_patterns]] allows. |
alt (required) | string | - | The text alternative. Use "" for a decorative image. |
width (required) | number | - | The rendered width in CSS pixels. Sets the width attribute and picks the 1x/2x candidates. Not used with fill. |
height (required) | number | - | The rendered height in CSS pixels, for the height attribute, so the browser reserves the space before the image loads. Not used with fill. |
priority | boolean | false | Load eagerly with fetchpriority="high" and preload the image in the document head. For the largest image above the fold. |
quality | number | [images] quality (75) | Encoder quality, rounded and clamped to 1-100. |
sizes | string | - | How wide the image renders per breakpoint ("(max-width: 768px) 100vw, 50vw"). Switches the srcset to every allowed width. |
fill | boolean | false | Fill the parent: no width/height attributes, width: 100%; height: 100%; object-fit: cover, and sizes defaulting to 100vw. |
placeholder | 'blur' | 'empty' | - | With 'blur' and a blurDataURL, show that image behind this one while it loads. 'empty' or no value shows nothing. |
blurDataURL | string | - | The placeholder image, usually a tiny base64 data: URL. Used only with placeholder="blur". |
unoptimized | boolean | false | Skip the optimizer and render src as is. |
className | string | - | Passed to the <img>. |
GioImage takes only these props: id, style, onLoad, decoding and other <img> attributes are not forwarded. Style it through className.
How the srcset is built
Every URL is /_gio/image?src=<encoded src>&w=<width>&q=<quality>. The optimizer answers 400 for any width outside [images] allowed_widths, so the widths come from exactly that list - the server hands it to the renderer, and the page carries it to the browser, so the hydrated markup matches the server's.
- Fixed size (no
sizes, nofill): a1xcandidate at the smallest allowed width that coverswidth, and a2xone covering twice that (left out when it is the same width).srcis the2xURL. A width above every allowed width uses the largest. - With
sizesorfill: every allowed width as awdescriptor,srcat the largest, and thesizesattribute (100vwwhen onlyfillis set). The browser picks by layout width and screen density. - An empty
allowed_widthslist, or awidthof0withoutsizes, requests no width at all: one URL, converted but not resized.
With the default allowed_widths, <GioImage src="/hero.png" alt="Hero" width={400} height={300} /> renders (line breaks added):
<img src="/_gio/image?src=%2Fhero.png&w=828&q=75"
srcSet="/_gio/image?src=%2Fhero.png&w=640&q=75 1x, /_gio/image?src=%2Fhero.png&w=828&q=75 2x"
width="400" height="300" alt="Hero" loading="lazy"/>Plain src
GioImage renders src untouched, with no srcset, when:
unoptimizedis set;- the source is an SVG (a path ending in
.svg, any case, before?or#), adata:URL or ablob:URL; - the page comes from
gio export- a static host has no optimizer; gio.tomlturns the optimizer off with[images] enabled = false(/_gio/imagethen answers404).
placeholder and blurDataURL
placeholder="blur" with a blurDataURL sets that URL as the <img>'s CSS background (background-size: cover), so a blurred preview fills the box until the real image paints over it. GioJS does not generate the preview: produce a tiny image (10-20 pixels wide) when you store the original, and pass it as a base64 data: URL. Without a blurDataURL, placeholder="blur" does nothing.
priority
A priority image renders with loading="eager" and fetchpriority="high", and React's server renderer adds a <link rel="preload" as="image"> with the same imagesrcset and imagesizes to the head, so the browser starts the download before it reaches the <img>. Every other image is loading="lazy".
Examples
A responsive hero image
import { GioImage } from '@gio.js/react';
export default function Home() {
return (
<GioImage
src="/hero.jpg"
alt="The harbor at dawn"
width={1600}
height={900}
sizes="(max-width: 768px) 100vw, 60vw"
priority
/>
);
}Filling a container
With fill the parent decides the size. GioImage sets no positioning, so give the parent a size, for example with aspect-ratio.
import { GioImage } from '@gio.js/react';
import styles from './cover.module.css';
export function Cover({ src, alt }: { src: string; alt: string }) {
return (
<div className={styles.cover}>
<GioImage src={src} alt={alt} width={0} height={0} fill sizes="(max-width: 960px) 100vw, 960px" />
</div>
);
}.cover {
aspect-ratio: 16 / 9;
overflow: hidden;
border-radius: 12px;
}A blurred preview
import { GioImage } from '@gio.js/react';
interface Photo {
url: string;
alt: string;
width: number;
height: number;
preview: string; // 'data:image/webp;base64,...', made when the photo was uploaded
}
export default function PhotoPage({ photo }: { photo: Photo }) {
return (
<GioImage
src={photo.url}
alt={photo.alt}
width={photo.width}
height={photo.height}
sizes="100vw"
placeholder="blur"
blurDataURL={photo.preview}
/>
);
}A remote image
Allow the host in gio.toml; anything not on the list is refused.
[[images.remote_patterns]]
protocol = "https"
hostname = "images.example.com"
pathname = "/uploads/*"<GioImage src="https://images.example.com/uploads/team.jpg" alt="The team" width={800} height={533} />An animated GIF
<GioImage src="/loading.gif" alt="" width={64} height={64} unoptimized />Good to know
- The blur preview stays behind the image after it loads: transparent areas of a PNG or WebP show it. Use
placeholder="blur"for opaque photos. fillandplaceholder="blur"render astyleattribute. Under a Content Security Policy,style-srcmust allow'unsafe-inline'for them.- The optimizer caches each width under a name that ignores the source's content: replacing
public/hero.jpgkeeps serving the old resized copies. Give a changed image a new file name. - A
qualityper image adds new URLs to the optimizer's cache; keep to a few values. - Prefer pre-sized files in a static export: every image is served as is.
- Path traversal, redirects on remote sources and guard checks on
public/files are enforced by the optimizer and cannot be turned off; the size and time limits can (see[images]).
Related
- Image Optimization - formats, caching, remote images and limits.
[images]-allowed_widths,quality,formats,enabled.publicfolder - where local images live.- Static Export - images without a server.
Version history
| Version | Changes |
|---|---|
v0.1.0-beta.8 | Requests only the widths in [images] allowed_widths, with [images] quality as the default. priority preloads the image. Added unoptimized; SVG, data: and blob: sources, static exports and [images] enabled = false render the plain src. |
v0.1.0-beta.1 | Introduced. |