Staaarter

Outfit Builder

A mix-and-match selector across four categories (Top, Bottom, Shoes, Accessory) with a running total that recomputes live as you swap items. Built for apparel product pages that want to sell a full look, not just a single item.

By Staaarter Team
Ecommerce
Docs
Live preview

Docs

Installation

A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its button dependencies and any missing npm packages, and installs them straight into your project.

npx shadcn add https://staaarter.com/r/outfit-builder.json

Prefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/ecommerce/ecommerce27.tsx instead.

Usage

The file also exports ecommerce27Demo, the exact props behind the preview above. Spread it to get a working section in one line, then replace it with your own data.

import { Ecommerce27, ecommerce27Demo } from "@/components/blocks/ecommerce/ecommerce27";

export default function Page() {
  return <Ecommerce27 {...ecommerce27Demo} />;
}

Props

PropTypeDefaultDescription
headingstring"Build your outfit"Heading above the category rows.
descriptionstring"Pick one item per category and see the total update as you go."Supporting sentence under the heading.
categoriesOutfitCategory[][]Category rows, each rendered as its own radio group.
ctaLabelstring"Add all to cart"Label for the bottom call-to-action button.
classNamestringnoneExtra classes for the outer section element.

Types

type OutfitItem = {
  id: string;
  name: string;
  price: number; // dollars; formatted with toFixed(2) at render, never pre-formatted
  image?: { src: string; alt: string };
};

type OutfitCategory = {
  name: string; // also used as the native radio group's `name` attribute
  items: OutfitItem[];
};

Behavior notes

  • Each category row is a real native <input type="radio"> group (grouped by category.name), so exactly one item per category is selectable, and it's fully keyboard operable, the swatch card is just a styled <label> wrapping a visually hidden input.
  • The first item in each category is preselected on mount so the running total is never $0.00 on first render.
  • The running total is computed inline on every render from the four currently-selected item prices, it is not stored in state and synced via an effect.
  • "Add all to cart" has no click handler; it reflects the current total but doesn't perform a real add-to-cart action.
  • A category with no items simply renders an empty swatch row rather than being hidden, since that would silently drop it from the running total logic.