Vue Integration

Learn how to use OPTIMAGE with Vue 3. Create reusable components and composables for optimized responsive images.

Introduction

OPTIMAGE integrates seamlessly with Vue 3. Since OPTIMAGE serves standard image URLs, no additional packages are required. Use the Composition API for clean, reusable image handling.

No dependencies required! OPTIMAGE provides standard image URLs that work with any Vue setup - Vue CLI, Vite, Nuxt, and more.

Basic Usage

The simplest way to use OPTIMAGE in Vue is with a standard img element:

<template>
  <img
    src="https://cdn.optimage.com/col_abc123/768/hero-banner.webp"
    :srcset="srcset"
    sizes="100vw"
    alt="Hero banner"
    loading="lazy"
  />
</template>

<script setup 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>

OptimizedImage Component

Create a reusable component to simplify usage across your application:

<!-- components/OptimizedImage.vue -->
<template>
  <img
    :src="src"
    :srcset="srcset"
    :sizes="sizes"
    :alt="alt"
    :loading="priority ? 'eager' : 'lazy'"
    :decoding="priority ? 'sync' : 'async'"
    :class="className"
  />
</template>

<script setup lang="ts">
import { computed } from 'vue';

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;
  className?: string;
}

const props = withDefaults(defineProps<Props>(), {
  sizes: '100vw',
  priority: false,
  className: '',
});

const src = computed(() =>
  `${CDN_URL}/${props.collectionId}/768/${props.slug}.webp`
);

const srcset = computed(() =>
  SIZES
    .map(size => `${CDN_URL}/${props.collectionId}/${size}/${props.slug}.webp ${size}w`)
    .join(', ')
);
</script>

Usage

<template>
  <div class="product-card">
    <OptimizedImage
      collection-id="col_products"
      :slug="product.imageSlug"
      :alt="product.name"
      sizes="(max-width: 768px) 100vw, 33vw"
      class-name="w-full h-48 object-cover rounded-lg"
    />
    <h3>{{ product.name }}</h3>
  </div>
</template>

<script setup lang="ts">
import OptimizedImage from './components/OptimizedImage.vue';

defineProps<{
  product: {
    imageSlug: string;
    name: string;
  };
}>();
</script>

useOptimage Composable

For more flexibility, create a composable that generates URLs:

// composables/useOptimage.ts
import { computed, toValue, type MaybeRef } from 'vue';

const SIZES = [320, 384, 448, 512, 576, 672, 768, 896, 1024, 1152, 1280];
const CDN_URL = 'https://cdn.optimage.com';

export function useOptimage(
  collectionId: MaybeRef<string>,
  slug: MaybeRef<string>
) {
  const getUrl = (size: number) =>
    `${CDN_URL}/${toValue(collectionId)}/${size}/${toValue(slug)}.webp`;

  const src = computed(() => getUrl(768));

  const srcset = computed(() =>
    SIZES
      .map(size => `${getUrl(size)} ${size}w`)
      .join(', ')
  );

  return {
    src,
    srcset,
    getUrl,
  };
}

Usage

<template>
  <div>
    <!-- Using store values -->
    <img
      :src="src"
      :srcset="srcset"
      sizes="64px"
      :alt="name"
      class="w-16 h-16 rounded-full"
    />

    <!-- Using getUrl for specific size -->
    <img
      :src="getUrl(320)"
      :alt="name"
      class="w-8 h-8 rounded-full"
    />
  </div>
</template>

<script setup lang="ts">
import { useOptimage } from './composables/useOptimage';

const props = defineProps<{
  userId: string;
  name: string;
}>();

const { src, srcset, getUrl } = useOptimage('col_avatars', props.userId);
</script>

Nuxt Integration

For Nuxt 3, you can use the same components and composables. Place them in the appropriate directories:

Directory Structure

your-nuxt-app/
├── components/
│   └── OptimizedImage.vue  # Auto-imported
├── composables/
│   └── useOptimage.ts      # Auto-imported
└── pages/
    └── index.vue

Usage in Nuxt

<!-- pages/index.vue -->
<template>
  <div>
    <!-- Component is auto-imported -->
    <OptimizedImage
      collection-id="col_hero"
      slug="homepage-banner"
      alt="Welcome to our site"
      :priority="true"
    />
  </div>
</template>

<script setup lang="ts">
// Composable is auto-imported
const { src } = useOptimage('col_hero', 'homepage-banner');

// Use for SEO
useHead({
  meta: [
    { property: 'og:image', content: src.value },
  ],
});
</script>

Tip: Nuxt 3 auto-imports components from components/ and composables from composables/. No manual imports needed!

TypeScript Types

Define types for your OPTIMAGE integration:

// 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_SIZES: OptimageSize[] = [
  320, 384, 448, 512, 576, 672, 768, 896, 1024, 1152, 1280
];

export const CDN_URL = 'https://cdn.optimage.com';

Best Practices

  • 1.Use computed properties: Leverage Vue's reactivity for dynamic image URLs.
  • 2.Set priority for LCP images: Use priority prop for above-the-fold images.
  • 3.Prevent layout shift: Use aspect-ratio or fixed dimensions.
  • 4.Use kebab-case for props: In templates, use collection-id instead of collectionId.

Complete Gallery Example

<template>
  <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
    <OptimizedImage
      v-for="(image, index) in images"
      :key="image.slug"
      collection-id="col_gallery"
      :slug="image.slug"
      :alt="image.alt"
      sizes="(max-width: 768px) 100vw, 33vw"
      :priority="index < 3"
      class-name="w-full aspect-square object-cover rounded-lg"
    />
  </div>
</template>

<script setup lang="ts">
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>