# Defaults: ProductGallery (/themes/sdk/reference/product/defaults-3)

```ts
import { … } from '@poltura/theme-sdk/product';
```

## `ProductGallery` [#productgallery]

The nearest product's gallery, following the picked variant's image.

```ts
ProductGallery(props: ProductGalleryProps): ReactElement
```

**Props:** [`ProductGalleryProps`](/themes/sdk/reference/product/types-5#productgalleryprops)

<Tab value='Example'>

```tsx
import { ProductGallery } from '@poltura/theme-sdk/product';

export function Media() {
  return <ProductGallery layout='carousel' aspect='portrait' />;
}
```

</Tab>
<Tab value='Source'>

```tsx title="source/product-gallery.tsx"
import type { ReactElement } from 'react';
import { ChevronLeft, ChevronRight } from 'lucide-react';
import { useTranslations } from '@poltura/theme-sdk/i18n';
import {
  ProductGalleryImage,
  ProductGalleryThumbs,
  useProductGallery,
  type ProductGalleryProps,
} from '@poltura/theme-sdk/product';
import { cn } from '@poltura/theme-sdk/ui';

const STEP_BUTTON =
  'absolute top-1/2 z-10 flex size-10 -translate-y-1/2 items-center justify-center rounded-lg bg-foreground/50 text-background transition-colors hover:bg-foreground/70';

export function ProductGallery({
  layout = 'grid',
  aspect = 'square',
  className,
}: ProductGalleryProps): ReactElement {
  const gallery = useProductGallery();
  const t = useTranslations('product');
  const { images } = gallery;
  if (layout === 'carousel' && images.length > 1) {
    return (
      <div className={cn('flex min-w-0 flex-col gap-2', className)}>
        <div className='relative'>
          <ProductGalleryImage image={images[gallery.active] ?? null} aspect={aspect} priority />
          <button
            type='button'
            onClick={gallery.previous}
            aria-label={t('previousImage')}
            className={cn(STEP_BUTTON, 'left-2')}
          >
            <ChevronLeft aria-hidden='true' className='size-6' />
          </button>
          <button
            type='button'
            onClick={gallery.next}
            aria-label={t('nextImage')}
            className={cn(STEP_BUTTON, 'right-2')}
          >
            <ChevronRight aria-hidden='true' className='size-6' />
          </button>
        </div>
        <ProductGalleryThumbs images={images} active={gallery.active} onSelect={gallery.select} />
      </div>
    );
  }
  const [first, ...rest] = layout === 'grid' ? images : images.slice(0, 1);
  return (
    <div className={cn('flex min-w-0 flex-col gap-2', className)}>
      <ProductGalleryImage image={first ?? null} aspect={aspect} priority />
      {rest.length > 0 ? (
        <span className='grid grid-cols-2 gap-2'>
          {rest.map((image, index) => (
            <ProductGalleryImage key={`${image.url}:${index}`} image={image} aspect={aspect} />
          ))}
        </span>
      ) : null}
    </div>
  );
}
```

</Tab>


**See also:** [`useProductGallery`](/themes/sdk/reference/product/hooks-1#useproductgallery), [`ProductGalleryImage`](/themes/sdk/reference/product/parts-2#productgalleryimage), [`ProductGalleryThumbs`](/themes/sdk/reference/product/parts-2#productgallerythumbs)
