Products and listings SDK reference

Product, collection, search, review, variant and recommendation views.

Import these public values from @upstorr/theme-sdk/v1. Do not import their internal source files.

buildThemeProductRecommendationsUrl

buildThemeProductRecommendationsUrl(input: ThemeProductRecommendationsInput): string

createThemeCollectionCardView

createThemeCollectionCardView<TCollection extends { id?: string | null; title?: string | null; handle?: string | null; url?: string | null; }>(input: { collectionSetting: unknown; closestCollection?: TCollection | null; title?: unknown; label?: unknown; link?: unknown; }): { readonly collection: TCollection | { id: string; handle: string; title: string; imageUrl: string | null; url: string | null; } | null; readonly title: string; readonly href: string; readonly isPlaceholder: boolean; }

createThemeCollectionCountView

createThemeCollectionCountView(value: unknown): { readonly visible: false; readonly count: 0; } | { readonly visible: true; readonly count: number; }

createThemeCollectionLinksView

createThemeCollectionLinksView<TCollection extends { id: string; title: string; handle: string; imageUrl?: string | null; products_count?: number | null; all_products_count?: number | null; }>(input: { collections: TCollection[]; activeCollection?: { id?: string | null; handle?: string | null; } | null; showCount: boolean; }): { readonly collections: TCollection[]; readonly initialActiveIndex: number; readonly locals: (collection: TCollection, index: number, activeCollectionId: string | null) => { current: boolean; loading: string | undefined; count: string | number; count_value: string | number; placeholder_name: string; index: number; }; }

createThemeCollectionListingView

createThemeCollectionListingView<TProduct>(collection: ThemeCollectionListing<TProduct> | null | undefined): { readonly products: TProduct[]; readonly isEmpty: boolean; readonly resetHref: string; readonly pagination: ThemePaginationView; readonly loadMore: ThemePaginationDirectionView; }

createThemeCollectionListView

createThemeCollectionListView<TCollection extends { id: string; title: string; handle: string; imageUrl?: string | null; }>(input: { sectionType: string; collectionListSetting: unknown; collections: TCollection[]; collectionsProvided: boolean; layout: unknown; columns: unknown; maxCollections: unknown; }): { readonly collections: TCollection[]; readonly selectedReferences: string[]; readonly limit: number; }

createThemeCustomerReviewsView

createThemeCustomerReviewsView<TReview extends ThemeReviewInput>(input: { productReviews?: ThemeReviewsInput<TReview> | null; reviewsCount: unknown; columns: unknown; initialReviews: unknown; reviewsPerClick: unknown; }): { readonly reviews: TReview[]; readonly columns: number; readonly initialReviews: number; readonly reviewsPerClick: number; readonly canShowMore: boolean; readonly loop: (index: number) => { index: number; index0: number; first: boolean; last: boolean; length: number; }; }

createThemeFiltersView

createThemeFiltersView(input: { search?: ThemeFilterSource | null; collection?: ThemeFilterSource | null; products?: ThemeListingProduct[]; resultsSize?: unknown; currentCurrency: string; showFilterLabel: boolean; }): ThemeFiltersView

createThemeGiftCardLineMetadata

createThemeGiftCardLineMetadata(input: ThemeGiftCardPurchaseInput): ThemeCartLineMetadata

createThemePaginationView

createThemePaginationView(input: { pagination?: ThemeListingPagination | null; total: number; hrefForPage: (page: number) => ThemeListingHref; }): ThemePaginationView

createThemeProductAvailabilityView

createThemeProductAvailabilityView(product: ThemeProductPurchaseProduct | null | undefined): { readonly available: boolean; }

createThemeProductBadgeView

createThemeProductBadgeView(product: ThemeProductPurchaseProduct, selectedVariant?: ThemeProductPurchaseVariant | null): { visible: boolean; kind: "sold-out" | "sale"; label: string; }

createThemeProductCartLineMetadata

createThemeProductCartLineMetadata(input: { isGiftCardProduct: boolean; giftCardPurchase: ThemeGiftCardPurchaseForm; customProperties: ThemeProductCustomPropertyCollection | null; }): ThemeCartLineMetadata | null

createThemeProductCustomProperties

createThemeProductCustomProperties(collection: ThemeProductCustomPropertyCollection | null): Record<string, string> | null

createThemeProductHotspotView

createThemeProductHotspotView(product: ThemeProductPurchaseProduct | null | undefined, currentCurrency: string): ThemeProductHotspotView

createThemeProductInformationView

createThemeProductInformationView<TVariant extends ThemeProductPurchaseVariant, TProduct extends ThemeProductPurchaseProduct<TVariant>>(input: { product: TProduct; selectedVariant?: TVariant | null; hasMediaBlock: boolean; hideUnselectedVariantMedia: boolean; recommendationProducts: TProduct[]; }): { readonly hasMedia: boolean; readonly mediaImages: string[]; readonly recommendations: { readonly performed: boolean; readonly products: TProduct[]; readonly products_count: number; }; }

createThemeProductInventoryView

createThemeProductInventoryView(product: ThemeProductPurchaseProduct | null | undefined, selectedVariant: ThemeProductPurchaseVariant | null | undefined, options: { threshold: unknown; showQuantity: boolean; }): { visible: boolean; productId: string; status: "in_stock" | "out_of_stock" | "low"; label: string; }

createThemeProductListButtonView

createThemeProductListButtonView(collection: { handle?: unknown; url?: unknown; products_count?: unknown; all_products_count?: unknown; products?: unknown[]; } | null | undefined, maxProducts: unknown): { readonly visible: boolean; readonly href: string; }

createThemeProductListView

createThemeProductListView<TProduct, TCollection extends { id: string; title: string; handle: string; products_count?: number | null; }>(input: { products: TProduct[]; maxProducts: unknown; collection?: TCollection | null; collectionSetting?: unknown; }): { readonly limit: number; readonly products: TProduct[]; readonly items: (TProduct | null)[]; readonly collection: { id: string; handle: string; title: string; products: TProduct[]; products_count: number; } | null; }

createThemeProductMetafieldsView

createThemeProductMetafieldsView(product: { metadata?: Record<string, unknown> | null; category?: { template?: unknown; } | null; }): { key: string; label: string; value: string; }[]

createThemeProductPriceView

createThemeProductPriceView(product: ThemeProductPurchaseProduct | null | undefined, selectedVariant: ThemeProductPurchaseVariant | null | undefined, options: { currencyCode: string; showCurrencyCode?: boolean; showSalePriceFirst?: boolean; }): ThemeProductPriceView

createThemeProductPurchaseVariants

createThemeProductPurchaseVariants<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant>): TVariant[]

createThemeProductQuickAddView

createThemeProductQuickAddView<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant> & { options?: Array<{ name?: string; values?: string[]; }>; }, variants: TVariant[], isPurchasable: boolean, isUpdating: boolean): { readonly mode: "add" | "choose"; readonly optionCount: number; readonly canAdd: boolean; readonly disabled: boolean; readonly addLabel: "Adding" | "Add"; readonly addAriaLabel: "Add"; readonly chooseLabel: "Choose"; readonly chooseAriaLabel: "Choose"; }

createThemeProductRatingView

createThemeProductRatingView(input: { reviewSummary?: ThemeReviewSummaryInput | null; starsStyle: string; showNumber: boolean; }): { readonly value: number; readonly scaleMax: 5; readonly stars: ThemeReviewStarView[]; readonly filledStars: number; readonly showNumber: boolean; readonly ratingLabel: string; readonly reviewCount: number; readonly reviewCountLabel: `${number} Reviews`; readonly ariaLabel: `${number} out of 5 stars`; } | null

createThemeProductRecommendationsContext

createThemeProductRecommendationsContext<TProduct>(products: TProduct[], performed: boolean): { readonly performed: boolean; readonly products: TProduct[]; readonly products_count: number; }

createThemeProductRecommendationsView

createThemeProductRecommendationsView<TProduct extends ThemeProductPurchaseProduct>(input: { products: TProduct[]; closestProduct: TProduct | null | undefined; productReference?: unknown; maxProducts: unknown; baseUrl: string; sectionId?: string; }): { readonly mode: "products" | "placeholders" | "skeletons"; readonly products: TProduct[]; readonly items: { key: string; kind: "product"; product: TProduct; index: number; resourceId: string; }[] | { key: string; kind: "placeholder" | "skeleton"; product: null; index: number; resourceId: string; }[]; readonly listItems: (TProduct | null)[]; readonly hasVisibleItems: boolean; readonly hasProductContext: boolean; readonly recommendations: { readonly performed: boolean; readonly products: TProduct[]; readonly products_count: number; }; readonly runtimeProps: { readonly 'data-url': string; readonly 'data-section-id': string | undefined; readonly 'data-product-id': string | undefined; readonly 'data-intent': string; readonly 'data-recommendations-performed': "true" | "false"; }; }

createThemeProductStickyBarView

createThemeProductStickyBarView(product: ThemeProductPurchaseProduct, selectedVariant: ThemeProductPurchaseVariant | null | undefined, canAddToCart: boolean): { readonly title: string; readonly image: string | null; readonly variantTitle: string; readonly canAddToCart: boolean; }

createThemeProductSwatchValues

createThemeProductSwatchValues<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant>, showVariantImage: boolean): ThemeProductSwatchView[]

createThemeProductVariantPickerView

createThemeProductVariantPickerView<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant> & { options?: Array<{ name?: string; values?: string[]; }>; }, variants: TVariant[], selectedVariantId: string): { visible: boolean; groups: { key: string; name: string; optionIndex: number; selectedValue: string; variantIdForValue: (value: string) => string | null; choices: { value: string; variant: TVariant | null; variantId: string | null; selected: boolean; disabled: boolean; }[]; }[]; }

createThemeQuickOrderListView

createThemeQuickOrderListView<TProduct extends ThemeProductPurchaseProduct>(input: { products: TProduct[]; variantsPerPage: unknown; showImage: boolean; showSku: boolean; }): { readonly items: { key: string; product: TProduct; title: string; href: string; image: string; sku: string; }[]; readonly limit: number; }

createThemeReviewBreakdownView

createThemeReviewBreakdownView<TReview extends ThemeReviewInput>(productReviews: ThemeReviewsInput<TReview> | null | undefined, showEmptyRows: boolean): { readonly visible: boolean; readonly totalReviews: number; readonly rows: { rating: number; count: number; percentage: number; }[]; }

createThemeReviewCardView

createThemeReviewCardView<TReview extends ThemeReviewInput>(review: TReview): { readonly review: TReview; readonly reviewerName: string; readonly dateLabel: string; readonly media: ({ type: "image"; src: string; } | { type: "video"; src: string; })[]; readonly stars: ThemeReviewStarView[]; }

createThemeReviewStars

createThemeReviewStars(value: unknown, scaleMax?: number, snapHalf?: boolean): ThemeReviewStarView[]

createThemeSearchInputView

createThemeSearchInputView(input: { query: unknown; resultsCount: unknown; searchUrl: string; noResultsTemplate: string; }): { readonly query: string; readonly showNoResults: boolean; readonly noResultsText: string; readonly resetHref: string; }

createThemeSearchListingView

createThemeSearchListingView<TProduct>(input: { products: TProduct[]; resultsCount: unknown; pagination?: ThemeListingPagination | null; currentUrl?: string | null; }): { readonly products: TProduct[]; readonly resultsCount: number; readonly isEmpty: boolean; readonly pagination: ThemePaginationView; readonly loadMore: ThemePaginationDirectionView; }

createThemeVariantSwatchView

createThemeVariantSwatchView(value: string, variant: ThemeProductPurchaseVariant | null | undefined, showVariantImage: boolean): { value: string; isVariantImage: boolean; }

formatThemeReviewDate

formatThemeReviewDate(value: unknown): string

getFirstThemeProductVariant

getFirstThemeProductVariant<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant> | null | undefined): TVariant | null

getThemeProductImages

getThemeProductImages(product: ThemeProductPurchaseProduct | null | undefined): string[]

getThemeProductPageMediaImages

getThemeProductPageMediaImages<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant>, selectedVariant?: TVariant | null, hideUnselectedVariantMedia?: boolean): string[]

getThemeProductRecommendationsProps

getThemeProductRecommendationsProps(input: ThemeProductRecommendationsInput): { readonly 'data-url': string; readonly 'data-section-id': string | undefined; readonly 'data-product-id': string | undefined; readonly 'data-intent': string; readonly 'data-recommendations-performed': "true" | "false"; }

getThemeProductVariantImage

getThemeProductVariantImage(variant: ThemeProductPurchaseVariant | null | undefined): string

getThemeProductVariantImages

getThemeProductVariantImages(variant: ThemeProductPurchaseVariant | null | undefined): string[]

getThemeProductVariantOptionValue

getThemeProductVariantOptionValue(variant: ThemeProductPurchaseVariant | null | undefined, optionName: string | undefined, optionIndex: number): string

getThemeProductVariants

getThemeProductVariants<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant> | null | undefined): TVariant[]

hasThemeProductVariantChoices

hasThemeProductVariantChoices(product: ThemeProductPurchaseProduct | null | undefined): boolean

isThemeProductOnSale

isThemeProductOnSale(product: ThemeProductPurchaseProduct, selectedVariant?: ThemeProductPurchaseVariant | null): boolean

normalizeThemeProductPurchaseQuantity

normalizeThemeProductPurchaseQuantity(value: unknown): number

readThemeProductReference

readThemeProductReference(value: unknown): string

readThemeSearchRouteData

readThemeSearchRouteData<TProduct = unknown, TSortOption = unknown, TFilter = unknown, TPagination = unknown>(data: unknown): ThemeSearchRouteData<TProduct, TSortOption, TFilter, TPagination>

resolveThemeProductImageAspectRatio

resolveThemeProductImageAspectRatio(requestedRatio: unknown, product: ThemeProductPurchaseProduct | null | undefined): string

selectInitialThemeProductVariantId

selectInitialThemeProductVariantId<TVariant extends ThemeProductPurchaseVariant>(product: ThemeProductPurchaseProduct<TVariant>, variants: TVariant[]): string

THEME_DEFAULT_GIFT_CARD_PURCHASE

THEME_DEFAULT_GIFT_CARD_PURCHASE: ThemeGiftCardPurchaseForm

THEME_DEFAULT_SORT_OPTIONS

THEME_DEFAULT_SORT_OPTIONS: ThemeSortOptionInput[]

ThemeFilterInput

type ThemeFilterInput = {
    type: 'boolean' | 'list' | 'price_range';
    label: string;
    param_name: string;
    values?: ThemeFilterValueInput[];
    active_values?: ThemeFilterValueInput[];
    min_value?: { value?: number | null } | null;
    max_value?: { value?: number | null } | null;
    range_max?: number | null;
    currency?: string | null;
    url_to_remove?: string | null;
};

ThemeFiltersView

type ThemeFiltersView = {
    productsCount: number;
    productsCountLabel: string;
    seeResultsLabel: string;
    filters: ThemeFilterView[];
    activePills: Array<{ key: string; label: string; href: string }>;
    activeFilterCount: number;
    currentSort: string;
    sortOptions: ThemeSortOptionInput[];
    defaultSort: string;
    resultsUrl: string;
    terms: string;
    currency: string;
};

ThemeFilterValueInput

type ThemeFilterValueInput = {
    value: string;
    label: string;
    count?: number;
    active?: boolean;
    url_to_remove?: string;
};

ThemeFilterValueView

type ThemeFilterValueView = ThemeFilterValueInput & {
    active: boolean;
    disabled: boolean;
};

ThemeFilterView

type ThemeFilterView = {
    type: ThemeFilterInput['type'];
    label: string;
    paramName: string;
    activeCount: number;
    values: ThemeFilterValueView[];
    price: null | {
        minValue: number | null;
        maxValue: number | null;
        highestPrice: number;
        highestPriceInput: string;
        highestPriceLabel: string;
        currency: string;
        currencyLabel: string;
        active: boolean;
    };
};

ThemeGiftCardPurchaseForm

type ThemeGiftCardPurchaseForm = {
    deliveryType: 'SELF' | 'RECIPIENT';
    recipientEmail: string;
    recipientName: string;
    recipientMessage: string;
    sendAt: string;
};

ThemeGiftCardPurchaseInput

type ThemeGiftCardPurchaseInput = {
    deliveryType?: 'SELF' | 'RECIPIENT';
    recipientEmail?: string | null;
    recipientName?: string | null;
    recipientMessage?: string | null;
    sendAt?: string | null;
};

ThemeListingHref

type ThemeListingHref = string;

ThemePaginationDirectionView

type ThemePaginationDirectionView = {
    available: boolean;
    page: number;
    href: ThemeListingHref;
};

ThemePaginationPartView

type ThemePaginationPartView = {
    key: string;
    kind: 'gap' | 'current' | 'link';
    page: number | null;
    label: string;
    href: ThemeListingHref | null;
};

ThemePaginationView

type ThemePaginationView = {
    currentPage: number;
    totalPages: number;
    visible: boolean;
    previous: ThemePaginationDirectionView;
    next: ThemePaginationDirectionView;
    pages: ThemePaginationPartView[];
};

ThemeProductCustomPropertyCollection

type ThemeProductCustomPropertyCollection = {
    controls: ThemeProductCustomPropertyControl[];
    reportInvalid: () => void;
};

ThemeProductCustomPropertyControl

type ThemeProductCustomPropertyControl = {
    name: string;
    type: string;
    value: string;
    disabled: boolean;
    checked: boolean;
    valid: boolean;
};

ThemeProductHotspotView

type ThemeProductHotspotView = {
    hasProduct: boolean;
    title: string;
    image: string | null;
    priceLabel: string;
    href: string;
    soldOut: boolean;
};

ThemeProductPriceView

type ThemeProductPriceView = {
    visible: boolean;
    currency: string;
    placeholderFormattedPrice: string;
    showComparePrice: boolean;
    regular: {
        hidden: boolean;
        formattedPrice: string;
    };
    sale: {
        hidden: boolean;
        items: Array<{
            kind: 'regular' | 'sale';
            assistiveLabel: string;
            formattedPrice: string;
        }>;
    };
};

ThemeProductPurchaseProduct

type ThemeProductPurchaseProduct<TVariant extends ThemeProductPurchaseVariant = ThemeProductPurchaseVariant> = {
    id: string;
    name?: string | null;
    title?: string | null;
    handle?: string | null;
    price?: number | null;
    salePrice?: number | null;
    inStock?: boolean;
    totalStock?: number | null;
    thumbnail?: string | null;
    images?: string[] | null;
    fulfillmentKind?: string | null;
    currency?: string | null;
    currencyCode?: string | null;
    selectedVariantId?: string | null;
    selectedVariant?: TVariant | null;
    variants?: TVariant[];
    productVariants?: TVariant[];
    options?: Array<{ name?: string; values?: string[] }>;
    metadata?: Record<string, unknown> | null;
    [key: string]: unknown;
};

ThemeProductPurchaseVariant

type ThemeProductPurchaseVariant = {
    id: string;
    name?: string | null;
    title?: string | null;
    sku?: string | null;
    price?: number | null;
    salePrice?: number | null;
    inStock?: boolean;
    totalStock?: number | null;
    thumbnail?: string | null;
    image?: string | null;
    imageUrl?: string | null;
    featuredImage?: string | null;
    featured_image?: string | null;
    images?: string[] | null;
    option1?: string | null;
    option2?: string | null;
    option3?: string | null;
    options?: Record<string, string> | Array<{ name?: string; value?: string }>;
    [key: string]: unknown;
};

ThemeProductRecommendationsInput

type ThemeProductRecommendationsInput = {
    baseUrl?: string | null;
    productId?: string | null;
    sectionId?: string | null;
    limit?: number | string | null;
    intent?: string | null;
    performed?: boolean;
};

ThemeProductSwatchView

type ThemeProductSwatchView = {
    label: string;
    value: string;
    isVariantImage: boolean;
};

ThemeReviewInput

type ThemeReviewInput = {
    id: string;
    rating: number;
    title?: string | null;
    comment?: string | null;
    reviewerName?: string | null;
    images?: string[];
    videos?: string[];
    verified?: boolean | null;
    adminResponse?: string | null;
    createdAt?: string | null;
    user?: { name?: string | null } | null;
};

ThemeReviewsInput

type ThemeReviewsInput<TReview extends ThemeReviewInput = ThemeReviewInput> = {
    reviews: TReview[];
    summary: ThemeReviewSummaryInput;
};

ThemeReviewStarView

type ThemeReviewStarView = {
    key: number;
    kind: 'full' | 'half' | 'empty';
    fillPercent: number;
};

ThemeReviewSummaryInput

type ThemeReviewSummaryInput = {
    totalReviews?: number | null;
    averageRating?: number | null;
    ratingBreakdown?: Array<{ rating: number; count: number }>;
};

ThemeSearchRouteData

type ThemeSearchRouteData<
    TProduct = unknown,
    TSortOption = unknown,
    TFilter = unknown,
    TPagination = unknown,
> = {
    query: string;
    products: TProduct[];
    resultsCount: number;
    emptyStateTitle: string;
    pagination: TPagination | null;
    sortBy: string;
    defaultSortBy: string;
    sortOptions: TSortOption[];
    filters: TFilter[];
    url: string;
    currentUrl: string;
};

ThemeSortOptionInput

type ThemeSortOptionInput = { value: string; name: string };

useThemeProductPurchase

useThemeProductPurchase<TVariant extends ThemeProductPurchaseVariant, TProduct extends ThemeProductPurchaseProduct<TVariant>>(input: { product: TProduct; checkoutUrl: string; collectCustomProperties: (source: HTMLElement | null | undefined, productId: string) => ThemeProductCustomPropertyCollection | null; }): { product: TProduct; variants: TVariant[]; selectedVariant: TVariant | null; selectedVariantId: string; setSelectedVariantId: import("react").Dispatch<import("react").SetStateAction<string>>; quantity: number; setQuantity: (value: unknown) => void; quantityView: { minimum: number; maximum: number; canDecrease: boolean; decreaseValue: number; increaseValue: number; }; isGiftCardProduct: boolean; giftCardPurchase: ThemeGiftCardPurchaseForm; setGiftCardPurchase: import("react").Dispatch<import("react").SetStateAction<ThemeGiftCardPurchaseForm>>; isPurchasable: boolean; statusMessage: string | null; errorMessage: string | null; isUpdating: boolean; addToCartView: { canSubmit: boolean; disabled: boolean; label: string; productId: string; variantId: string; quantitySuffix: string; }; variantPicker: { visible: boolean; groups: { key: string; name: string; optionIndex: number; selectedValue: string; variantIdForValue: (value: string) => string | null; choices: { value: string; variant: TVariant | null; variantId: string | null; selected: boolean; disabled: boolean; }[]; }[]; }; quickAddView: { readonly mode: "add" | "choose"; readonly optionCount: number; readonly canAdd: boolean; readonly disabled: boolean; readonly addLabel: "Adding" | "Add"; readonly addAriaLabel: "Add"; readonly chooseLabel: "Choose"; readonly chooseAriaLabel: "Choose"; }; addToCart: (source?: HTMLElement | null) => Promise<void>; buyNow: (source?: HTMLElement | null) => Promise<void>; }