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.svelte

Using 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 $derived for dynamic image URLs.
  • 2.Preload critical images: Use <link rel="preload"> in <svelte:head> for LCP images.
  • 3.Use the class prop pattern: Export className as class for better DX.
  • 4.Place components in $lib: Use SvelteKit's $lib alias 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>