Svelte Integration
Learn how to use OPTIMAGE with Svelte. Create reusable components and stores for optimized responsive images.
Introduction
OPTIMAGE integrates seamlessly with Svelte and SvelteKit. Since OPTIMAGE serves standard image URLs, no additional packages are required. Leverage Svelte's reactivity for clean, efficient image handling.
No dependencies required! OPTIMAGE provides standard image URLs that work with any Svelte setup - Svelte, SvelteKit, or Vite with Svelte.
Basic Usage
The simplest way to use OPTIMAGE in Svelte is with a standard img element:
<script lang="ts">
const srcset = `
https://cdn.optimage.com/col_abc123/320/hero-banner.webp 320w,
https://cdn.optimage.com/col_abc123/768/hero-banner.webp 768w,
https://cdn.optimage.com/col_abc123/1280/hero-banner.webp 1280w
`;
</script>
<img
src="https://cdn.optimage.com/col_abc123/768/hero-banner.webp"
{srcset}
sizes="100vw"
alt="Hero banner"
loading="lazy"
/>OptimizedImage Component
Create a reusable component to simplify usage across your application:
<!-- lib/components/OptimizedImage.svelte -->
<script lang="ts">
const SIZES = [320, 384, 448, 512, 576, 672, 768, 896, 1024, 1152, 1280];
const CDN_URL = 'https://cdn.optimage.com';
export let collectionId: string;
export let slug: string;
export let alt: string;
export let sizes: string = '100vw';
export let priority: boolean = false;
let className: string = '';
export { className as class };
$: src = `${CDN_URL}/${collectionId}/768/${slug}.webp`;
$: srcset = SIZES
.map(size => `${CDN_URL}/${collectionId}/${size}/${slug}.webp ${size}w`)
.join(', ');
</script>
<img
{src}
{srcset}
{sizes}
{alt}
loading={priority ? 'eager' : 'lazy'}
decoding={priority ? 'sync' : 'async'}
class={className}
/>Usage
<script lang="ts">
import OptimizedImage from '$lib/components/OptimizedImage.svelte';
export let product: {
imageSlug: string;
name: string;
};
</script>
<div class="product-card">
<OptimizedImage
collectionId="col_products"
slug={product.imageSlug}
alt={product.name}
sizes="(max-width: 768px) 100vw, 33vw"
class="w-full h-48 object-cover rounded-lg"
/>
<h3>{product.name}</h3>
</div>Svelte 5 Runes Version
For Svelte 5 with runes, use the new syntax:
<!-- lib/components/OptimizedImage.svelte (Svelte 5) -->
<script lang="ts">
const SIZES = [320, 384, 448, 512, 576, 672, 768, 896, 1024, 1152, 1280];
const CDN_URL = 'https://cdn.optimage.com';
interface Props {
collectionId: string;
slug: string;
alt: string;
sizes?: string;
priority?: boolean;
class?: string;
}
let {
collectionId,
slug,
alt,
sizes = '100vw',
priority = false,
class: className = '',
}: Props = $props();
const src = $derived(`${CDN_URL}/${collectionId}/768/${slug}.webp`);
const srcset = $derived(
SIZES
.map(size => `${CDN_URL}/${collectionId}/${size}/${slug}.webp ${size}w`)
.join(', ')
);
</script>
<img
{src}
{srcset}
{sizes}
{alt}
loading={priority ? 'eager' : 'lazy'}
decoding={priority ? 'sync' : 'async'}
class={className}
/>Optimage Store
Create a store for managing OPTIMAGE URLs and configuration:
// lib/stores/optimage.ts
import { readable } from 'svelte/store';
const SIZES = [320, 384, 448, 512, 576, 672, 768, 896, 1024, 1152, 1280] as const;
const CDN_URL = 'https://cdn.optimage.com';
export type OptimageSize = typeof SIZES[number];
export function createOptimageStore(collectionId: string, slug: string) {
const getUrl = (size: OptimageSize = 768) =>
`${CDN_URL}/${collectionId}/${size}/${slug}.webp`;
const src = readable(getUrl(768));
const srcset = readable(
SIZES.map(size => `${getUrl(size)} ${size}w`).join(', ')
);
return { src, srcset, getUrl };
}
// Utility function for one-off usage
export function getOptimageUrl(
collectionId: string,
slug: string,
size: OptimageSize = 768
): string {
return `${CDN_URL}/${collectionId}/${size}/${slug}.webp`;
}Usage
<script lang="ts">
import { createOptimageStore } from '$lib/stores/optimage';
export let userId: string;
export let name: string;
const avatar = createOptimageStore('col_avatars', userId);
</script>
<div>
<!-- Using store values -->
<img
src={$avatar.src}
srcset={$avatar.srcset}
sizes="64px"
alt={name}
class="w-16 h-16 rounded-full"
/>
<!-- Using getUrl for specific size -->
<img
src={avatar.getUrl(320)}
alt={name}
class="w-8 h-8 rounded-full"
/>
</div>SvelteKit Integration
SvelteKit works perfectly with OPTIMAGE. Here's how to structure your integration:
Directory Structure
src/
├── lib/
│ ├── components/
│ │ └── OptimizedImage.svelte
│ └── stores/
│ └── optimage.ts
└── routes/
└── +page.svelteUsing with Load Functions
<!-- routes/products/[slug]/+page.svelte -->
<script lang="ts">
import OptimizedImage from '$lib/components/OptimizedImage.svelte';
import type { PageData } from './$types';
export let data: PageData;
</script>
<svelte:head>
<!-- Preload LCP image -->
<link
rel="preload"
as="image"
href="https://cdn.optimage.com/col_products/1280/{data.product.slug}.webp"
/>
</svelte:head>
<article>
<OptimizedImage
collectionId="col_products"
slug={data.product.slug}
alt={data.product.name}
sizes="100vw"
priority={true}
class="w-full h-96 object-cover"
/>
<h1>{data.product.name}</h1>
<p>{data.product.description}</p>
</article>Server-Side OG Images
// routes/products/[slug]/+page.server.ts
import { getOptimageUrl } from '$lib/stores/optimage';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params }) => {
const product = await fetchProduct(params.slug);
return {
product,
meta: {
title: product.name,
description: product.description,
ogImage: getOptimageUrl('col_products', product.slug, 1280),
},
};
};TypeScript Types
Define types for your OPTIMAGE integration:
// lib/types/optimage.ts
export type OptimageSize =
| 320 | 384 | 448 | 512 | 576
| 672 | 768 | 896 | 1024 | 1152 | 1280;
export interface OptimageImage {
collectionId: string;
slug: string;
}
export const OPTIMAGE_CONFIG = {
cdnUrl: 'https://cdn.optimage.com',
sizes: [320, 384, 448, 512, 576, 672, 768, 896, 1024, 1152, 1280],
defaultSize: 768,
} as const;Best Practices
- 1.Use reactive statements: Leverage
$:or$derivedfor dynamic image URLs. - 2.Preload critical images: Use
<link rel="preload">in<svelte:head>for LCP images. - 3.Use the class prop pattern: Export
classNameasclassfor better DX. - 4.Place components in $lib: Use SvelteKit's
$libalias for clean imports.
Complete Gallery Example
<script lang="ts">
import OptimizedImage from '$lib/components/OptimizedImage.svelte';
const images = [
{ slug: 'sunset-beach', alt: 'Beautiful sunset at the beach' },
{ slug: 'mountain-view', alt: 'Snow-capped mountain peaks' },
{ slug: 'city-lights', alt: 'City skyline at night' },
];
</script>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
{#each images as image, index (image.slug)}
<OptimizedImage
collectionId="col_gallery"
slug={image.slug}
alt={image.alt}
sizes="(max-width: 768px) 100vw, 33vw"
priority={index < 3}
class="w-full aspect-square object-cover rounded-lg
hover:scale-105 transition-transform duration-300"
/>
{/each}
</div>