A made-to-order configurator that answers as you go: every option takes over the plate beside it, writes its own line into a running specification, and moves a total that is visible from the first question rather than revealed at the end.
A made-to-order configurator that answers as you go. Every option takes over the plate beside it, writes its own line into a running specification, and moves a total that is visible from the first question rather than revealed at the end.
Free block
This block is free. No license or account is required: install it with the CLI and use it in unlimited projects.
Radix flavor
npx shadcn add "https://ui.beste.co/r/product12"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/product12"That installs the block file, the badge7 eyebrow and button12 pill it is built from, and the questionnaire primitive.
import { Product12, product12Demo } from "@/components/beste/block/product12";
export default function Page() {
return <Product12 {...product12Demo} />;
}import { Product12 } from "@/components/beste/block/product12";
export default function Page() {
return (
<Product12
badge={{ label: "Made to order" }}
heading="Specify the chair while you look at it."
description="Every answer changes the plate and the line it writes."
shortcuts="numbers"
basePrice={480}
currency="£"
image={{
src: "https://images.unsplash.com/photo-1503602642458-232111445657",
alt: "Wooden chair standing alone in a bright room",
}}
caption="The Aro chair, built in the workshop in batches of twelve."
steps={[
{
name: "frame",
title: "Which frame?",
specLabel: "Frame",
choices: [
{
value: "oak",
label: "Oiled oak",
spec: "Oiled European oak",
price: 0,
// takes over the plate while it is the selected option
image: {
src: "https://images.unsplash.com/photo-1503602642458-232111445657",
alt: "Pale oak chair against a white wall",
},
caption: "Oak is the standing frame.",
},
{
value: "steel",
label: "Waxed steel",
spec: "Waxed steel, 16mm section",
price: 140,
},
],
},
{
name: "seat",
title: "What sits on it?",
specLabel: "Seat",
choices: [
{ value: "canvas", label: "Cotton canvas", spec: "16oz cotton canvas", price: 0 },
{ value: "leather", label: "Leather", spec: "Vegetable-tanned, 3mm", price: 180 },
],
},
]}
closing={{
title: "Specification sent",
description: "The workshop replies inside three working days.",
}}
button={{ label: "Book a workshop visit", href: "https://beste.co" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
badge | Badge | – | Parenthetical eyebrow above the heading, rendered with Badge7. |
heading | string | – | Section heading. |
description | string | – | Lead paragraph, set opposite the heading. |
steps | ConfigStep[] | [] | The questions, each writing one row of the specification. |
shortcuts | "letters" | "numbers" | – | Prints a shortcut on every choice of the active step. |
basePrice | number | 0 | Every chosen option's price is added to this. |
currency | string | "$" | Prefix printed in front of the total. |
image | ConfigImage | – | Plate shown before anything has been chosen. |
caption | string | – | Line under the standing plate. |
closing | Closing | – | Replaces the questions once the specification is sent. |
button | ActionButton | – | Button12 pill under the sent specification. |
labels | Product12Labels | {} | Overrides for the navigation buttons and the ledger copy. |
className | string | – | Merged onto the section element. |
type Badge = { label: string };
type ActionButton = { label: string; href: string };
type ConfigImage = { src: string; alt: string };
type Closing = { title: string; description: string };
type ConfigStep = {
name: string;
title: string;
description?: string;
specLabel: string;
choices?: ConfigChoice[];
};
type ConfigChoice = {
value: string;
label: string;
description?: string;
image?: ConfigImage;
caption?: string;
spec: string;
price?: number;
};
type Product12Labels = {
previous?: string;
next?: string;
submit?: string;
restart?: string;
specTitle?: string;
priceLabel?: string;
pending?: string;
};labels.pending for the rows still open, so nothing about the price arrives as a surprise.basePrice plus the price of every chosen option. A negative price is allowed, which is how a downgrade reads correctly rather than as a discount bolted on afterwards.image. The plate follows the last chosen option that carries one, so a frame can change the picture while a finish only changes the line it writes.product9
Clickable tabs switch a feature panel with a large product image, title, and description. Supports an optional auto-loop.
product2
A large product image flanked by numbered feature callout cards, each naming and describing a part of the product.
product10
Editorial grid of macro close-up shots, each captioned with the material or detail it shows.
product6
Variant explorer that swaps the product image and spec line as you click between finishes.