# Parts: ProductGalleryImage to ProductKeySpecs (/themes/sdk/reference/product/parts-2)

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

## `ProductGalleryImage` [#productgalleryimage]

One framed gallery image, cropped to the aspect, or the placeholder when there is none.

```ts
ProductGalleryImage(props: ProductGalleryImageProps): ReactElement
```

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

**Example**

```tsx
import { ProductGalleryImage, useProductGallery } from '@poltura/theme-sdk/product';

export function Cover() {
  const { images } = useProductGallery();
  return <ProductGalleryImage image={images[0] ?? null} aspect='portrait' priority />;
}
```

## `ProductGalleryThumbs` [#productgallerythumbs]

A row of thumbnails, the shown image's marked, each showing its image when pressed; nothing for fewer than two images.

```ts
ProductGalleryThumbs(props: ProductGalleryThumbsProps): ReactElement | null
```

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

**Example**

```tsx
import { ProductGalleryThumbs, useProductGallery } from '@poltura/theme-sdk/product';

export function Thumbs() {
  const gallery = useProductGallery();
  return <ProductGalleryThumbs images={gallery.images} active={gallery.active} onSelect={gallery.select} />;
}
```

## `BundleConfigurator` [#bundleconfigurator]

A standalone bundle: its items with the choice among them, the live price and an add-the-bundle-to-cart button.

```ts
BundleConfigurator(props: BundleConfiguratorProps): ReactElement
```

Pass a bundle the SDK handed out, such as from [`useProductBundles`](/themes/sdk/reference/product/hooks-2#useproductbundles); the part reads its full record on the host.

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

**Example**

```tsx
import { BundleConfigurator, useProductBundles } from '@poltura/theme-sdk/product';

export function Offer({ productId }: { productId: string }) {
  const bundle = useProductBundles({ productIds: [productId] }).data?.get(productId)?.[0];
  return bundle === undefined ? null : <BundleConfigurator bundle={bundle} />;
}
```

**See also:** [`useBundleQuote`](/themes/sdk/reference/product/hooks-1#usebundlequote)

## `BundleSuggestions` [#bundlesuggestions]

A panel of bundle offers with their saving, the reason each is suggested and a configure button.

```ts
BundleSuggestions(props: BundleSuggestionsProps): ReactElement | null
```

Pass bundles the SDK handed out, such as from [`useProductBundles`](/themes/sdk/reference/product/hooks-2#useproductbundles).

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

**Example**

```tsx
import { useState } from 'react';
import { BundleSuggestions, useProductBundles } from '@poltura/theme-sdk/product';

export function Offers({ productId }: { productId: string }) {
  const [active, setActive] = useState<string | null>(null);
  const bundles = useProductBundles({ productIds: [productId] }).data?.get(productId) ?? [];
  return <BundleSuggestions bundles={bundles} activeBundleId={active} onSelectBundle={setActive} />;
}
```

**See also:** [`useBundleRecommendations`](/themes/sdk/reference/product/hooks-1#usebundlerecommendations)

## `WishlistButton` [#wishlistbutton]

A heart button that saves a product to the shopper's favourites and takes it out again; nothing when the store has favourites turned off.

```ts
WishlistButton(props: WishlistButtonProps): ReactElement | null
```

A signed-in shopper's list is kept in their account and a guest's in the browser, where it joins the account on sign-in. The `card` placement is positioned absolutely, so put it inside a `relative` image box. The first product a browser ever saves shows a short note once; later saves show nothing.

**Props:** [`WishlistButtonProps`](/themes/sdk/reference/product/types-6#wishlistbuttonprops)

**Example**

```tsx
import type { ProductCard } from '@poltura/theme-sdk/listing';
import { WishlistButton } from '@poltura/theme-sdk/product';

export function Corner({ card }: { card: ProductCard }) {
  return (
    <WishlistButton
      productId={card.id}
      title={card.title}
      categoryLabel={card.categoryLabel}
      price={card.price}
    />
  );
}
```

## `WishlistLink` [#wishlistlink]

A heart with the number of saved products, linking to the shopper's favourites page; nothing when the store has favourites turned off.

```ts
WishlistLink(props: WishlistLinkProps): ReactElement | null
```

**Props:** [`WishlistLinkProps`](/themes/sdk/reference/product/types-6#wishlistlinkprops)

**Example**

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

export function HeaderActions() {
  return <WishlistLink />;
}
```

## `ProductBadges` [#productbadges]

A product's badges as colour-coded labels; nothing without badges.

```ts
ProductBadges(props: ProductBadgesProps): ReactElement | null
```

A tone follows the theme through the `--badge-<tone>` and `--badge-<tone>-foreground` custom properties, which a theme or colour scheme may set; a custom colour is drawn as the merchant set it. Without `--badge-<tone>` a tone paints with the theme's own colour: `dark` the primary colour, `accent` the focus ring colour, `red` the destructive colour, `green` the success colour, `amber` the warning colour, `blue` #1d5fa8. The text takes `--badge-<tone>-foreground` when it is set, else black or white by the lightness of the tone's colour. The shipped themes set all six in `tokens.css` and `tokens.dark.css`: `dark` and `red` point at the `--primary-foreground` and `--destructive-foreground` pair, so a colour edit keeps them readable, and the others hold the black or white that reads at WCAG AA (4.5:1) on the tone's colour. A theme that changes a tone colour sets its foreground with it. The platform also writes `--badge-accent-foreground` in the generated settings CSS whenever the merchant saves a focus ring colour, and `--badge-ring-foreground` in each colour scheme box, by the same black-or-white rule, so the accent tone stays readable after an edit.

**Props:** [`ProductBadgesProps`](/themes/sdk/reference/product/types-7#productbadgesprops)

**Example**

```tsx
import type { ProductCard } from '@poltura/theme-sdk/listing';
import { ProductBadges } from '@poltura/theme-sdk/product';

export function Corner({ card }: { card: ProductCard }) {
  return <ProductBadges badges={card.badges} placement='card' className='absolute left-2 top-2' />;
}
```

## `ProductKeySpecs` [#productkeyspecs]

The attributes the store shows by the product title, such as a game's platform: a small name over its values with their icons; nothing without any.

```ts
ProductKeySpecs(props: ProductKeySpecsProps): ReactElement | null
```

**Props:** [`ProductKeySpecsProps`](/themes/sdk/reference/product/types-7#productkeyspecsprops)

**Example**

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

export function UnderTitle() {
  return <ProductKeySpecs className='mt-2' />;
}
```

**See also:** [`useProductPage`](/themes/sdk/reference/product/hooks-2#useproductpage)
