Skip to content

Product Images ​

This guide describes how product images are fetched, processed, and displayed in the Bagisto Headless storefront, including support for base images and variant-specific galleries.

Overview ​

In Bagisto Headless, product photography is handled dynamically. The storefront retrieves image URLs from the GraphQL API and uses a specialized utility to resolve full paths. On the product detail page, a carousel component handles the display of multiple images, automatically switching between the main product gallery and variant-specific images based on user selection.

1. GraphQL Query & Fragments ​

Product image data is included in the ProductDetailed fragment, which is used by the GET_PRODUCT_BY_ID query.

Image Fields in Fragment ​

The baseImageUrl field provides the path to the product's primary image. For configurable products, variants also include their own baseImageUrl to allow for dynamic gallery updates.

File: src/graphql/catelog/fragments/Product.ts

graphql
fragment ProductDetailed on Product {
  # Main product image
  baseImageUrl
  
  # Variant-specific images
  variants {
    edges {
      node {
        id
        sku
        baseImageUrl
      }
    }
  }
}

2. Frontend Implementation ​

The storefront uses a combination of utility functions and components to provide a seamless image viewing experience.

Image URL Resolution ​

The getImageUrl utility ensures that image paths (whether relative or absolute) are correctly formatted and includes a fallback mechanism for missing images.

File: src/utils/constants.ts

typescript
export function getImageUrl(url?: string, baseUrl?: string, fallback?: string) {
  if (!url) return fallback;

  if (url.startsWith("http://") || url.startsWith("https://")) {
    return url;
  }

  return `${baseUrl}${url.startsWith("/") ? url : `/${url}`}`;
}

The HeroCarousel component is responsible for rendering the main product image and a thumbnail navigation list. It supports smooth transitions using Framer Motion.

File: src/components/common/slider/HeroCarousel.tsx

tsx
export default function HeroCarousel({ images }) {
  const [current, setCurrent] = React.useState(0);

  return (
    <div className="group relative overflow-hidden">
      <motion.div key={current} initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
        <Image
          fill
          src={images[current]?.src}
          alt={images[current]?.altText}
          className="object-cover"
        />
      </motion.div>
      
      {/* Thumbnail Navigation */}
      <ul className="flex gap-2 overflow-x-auto">
        {images.map((image, index) => (
          <li key={image.src}>
            <button onClick={() => setCurrent(index)}>
              <GridTileImage src={image.src} active={current === index} />
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

3. Dynamic Variant Images ​

One of the key features of the product page is its ability to switch the image gallery based on the selected variant.

Selection Logic ​

In the ProductPage component, the storefront checks if there are variant-specific images available. If a variant is selected (or if variants exist), it prioritizes those images over the base product image.

File: src/app/(public)/product/[...urlProduct]/page.tsx

tsx
// Extract variant images if they exist
const VariantImages = isArray(product?.variants?.edges)
  ? product?.variants.edges.map((edge) => edge.node)
  : [];

// Determine which images to pass to the carousel
const carouselImages = isArray(VariantImages) && VariantImages.length > 0
  ? VariantImages.map((image) => ({
      src: getImageUrl(image.baseImageUrl, baseUrl, NOT_IMAGE),
      altText: image?.name || product?.name,
    }))
  : [{
      src: getImageUrl(product?.baseImageUrl, baseUrl, NOT_IMAGE),
      altText: product?.name,
    }];

Summary ​

  • Multiple Image Sources: Supports both primary product images and variant-specific photography.
  • Path Resolution: Uses getImageUrl to handle both local and remote image sources.
  • Interactive Carousel: Features thumbnail navigation and smooth transitions.
  • Dynamic Updates: Automatically reflects the selected variant's images via React state and URL parameters.

Next Steps ​

Released under the MIT License.