Skip to main content

Showing Metafields on a Product Display Card

A Product List Item Display Card that shows two custom metafields (vendor and concentration_category) alongside the title and price, with a skeleton placeholder while the product is still loading.

Example

import React from 'react';
import { Actionable, Box, Flexbox, Image, Text, Button } from '@evlop/native-components';
import { Money, loadProductsManager, CustomBlock } from '@evlop/shopify';

loadProductsManager.addMetafieldIdentifiers([
{ namespace: 'custom', key: 'concentration_category' },
{ namespace: 'custom', key: 'vendor' },
]);

const skeleton = <Box borderRadius={5} bg="gray-100" style={{ aspectRatio: 1 }} />;

const ProductDisplayCard: CustomBlock.ProductListItem = ({ data }) => {
const { product } = data;
if (product?.isLoading) return skeleton;
return (
<Actionable action={product.actions.openDetailsPage}>
<Flexbox flexDirection="column" gap={10}>
<Flexbox flexDirection="column" gap={5}>
<Image
borderRadius={5}
resizeMode="cover"
src={product.images[0].url}
aspectRatio={1}
/>
</Flexbox>
<Flexbox flexDirection="column" gap={4} alignItems="center">
<Text fontSize="xs" textAlign="center">{product.metafields?.custom?.vendor}</Text>
<Text textAlign="center" numberOfLines={2} fontSize="sm" fontWeight="Bold">{product.title}</Text>
<Text fontSize="xs" textAlign="center">{product.metafields?.custom?.concentration_category}</Text>
<Money fontWeight="Bold" price={product.variants[0].price} />
</Flexbox>
</Flexbox>
</Actionable>
);
};

export default ProductDisplayCard;

How it works

  • Register the metafields once, at module scope. loadProductsManager.addMetafieldIdentifiers([{ namespace, key }, ...]) is called alongside the imports, outside the component function - never inside the render body. This tells the product loader which metafields to fetch for every product it loads.
  • Read them off product.metafields. A registered { namespace: 'custom', key: 'vendor' } identifier lands at product.metafields.custom.vendor. Access it with optional chaining (product.metafields?.custom?.vendor) since a metafield may be unset on a given product.
  • Guard the loading state first. product?.isLoading is checked before touching images/variants/metafields, returning a skeleton - a gray <Box> matching the card's own image dimensions - rather than rendering with data that isn't there yet.
  • Type the component. CustomBlock.ProductListItem (from @evlop/shopify) types data.product as a full ShopifyProduct, including the registered metafields, without needing to declare your own props interface.

See Product List Item Display Card for the rest of that block type's data shape, and Available Packages for what else @evlop/shopify exports.