Centra colour siblings dedupe by uri

Centra colour relations repeat the current product in relatedDisplayItems. I dedupe swatches by uri in domain so the PDP does not render Black twice.

Sander Korf2 min read
centranextjstailwind

Centra relatedDisplayItems for the colour-sibling relation is not a set. Import quirks and frontend auto-linking often put the current product in the sibling list twice. I built swatches as [current, ...siblings], sorted by uri, and watched Black show up twice on a Next.js PDP that was otherwise fine. Shoppers did not report a bug. They tapped the same swatch row and wondered why nothing changed.

The duplicate was data-shaped, not React-shaped. Two entries shared uri /linen-tee-black. One carried the live product id, the other an import shadow with the same uri and an empty slug. Sorting by uri kept them adjacent and made the UI look intentional. It was not.

Dedupe belongs in domain, on the display key you actually render. I wrapped the mapped swatches in dedupeByUri, keeping first occurrence for stable order, then toSorted by uri. Empty uri falls back to id so import duplicates without a slug still collapse.

function dedupeByUri<T extends { uri: string; id: string }>(items: T[]): T[] {
	const seen = new Set<string>();
	return items.filter((item) => {
		const key = item.uri || item.id;
		if (seen.has(key)) return false;
		seen.add(key);
		return true;
	});
}
 
const colourOptions = dedupeByUri([currentColour, ...siblingColours]).toSorted((a, b) =>
	(a.uri || a.id).localeCompare(b.uri || b.id)
);

The colour picker only renders when options.length >= 2, on the PDP and on Quick Add. One colour means no fake choice UI. Legend stays sr-only because legend is out of the fieldset flex flow in Tailwind. The visible "Colour" label is a separate div with aria-hidden so sighted layout and screen reader structure do not fight.

Quick Add size chips stopped using a one-off mail-icon button for unavailable sizes. They now go through the same ProductSizeOption component as the PDP: available vs unavailable styling, same hit target, same notify path later. Mobile PDP grid uses display: contents on the wrapper so order can be media, then info, then accordion without the info column height shoving the accordion down. Desktop stacks media and accordion in the left column while info stays an independent column.

Colour swatches after dedupeByUri

Centra relatedDisplayItems often repeats the current product. Toggle dedupe to see duplicate Black swatches from the same uri.

Colour

4 swatches rendered

Duplicate uri collapsed. Empty uri falls back to id so import duplicates still dedupe.

Toggle dedupe off in the demo. Black appears twice from the same uri. Turn it on and the list matches what Centra meant to sell.

PIM relations arrive as lists. Treat them like lists and dedupe on the key you paint.


Happy coding! Sander