Arrecho UI
The commerce design system every Arrecho storefront installs from — tokens, components, whole pages, and full-stack addons, served as source you own rather than a package you depend on. Change a token once and it updates everywhere.
What ships
6 layers and 108 items, each layer consuming the one above it. Everything lives under one namespace, so a single line of config reaches all of it.
Brand-invariant structure lives in @arrecho/foundation; a theme supplies values only, so one registry dresses many brands.
Button, dialog, table, field, sidebar — built on Base UI, drawn entirely from the tokens, never a hard-coded color.
@/components/ui/<name>
Full-width page sections — hero, feature row, testimonial, newsletter. Domain-neutral and prop-driven, so a section is reusable rather than a thing you gut.
@/components/sections/<name>
The storefront's own vocabulary — product card, price, variant picker, cart line, order summary. Part of the ecommerce addon rather than a tier of its own: these are the pieces its pages are built from.
@/components/ecommerce/<name>
Whole pages, composed from sections. Installing one writes a route; the layout it uses stays installable on its own.
app/<route>/page.tsx
Full-stack features: a Drizzle table, guarded server actions, and the UI that drives them. One install lands a working feature.
@/components/<addon>/*, @/server/<addon>/*
Point an app at it
// components.json
{ "registries": { "@arrecho": "https://registry.arrecho.tech/r/{name}.json" } }pnpm dlx shadcn@latest add @arrecho/foundation @arrecho/gruvbox
pnpm dlx shadcn@latest add @arrecho/product-card
pnpm dlx shadcn@latest add @arrecho/checkoutAlways with the @arrecho prefix — a bare shadcn add button resolves to shadcn's own registry and installs the Radix component instead of the Base UI one these apps are built on.
Using it
Installing writes source into your app. From there it is yours — imported by path, styled through tokens, and updated only when you ask.
Then import it
The item name and the import path are not the same thing. An item installs into the directory its type implies, resolved through the aliases in your components.json — so @arrecho/price lands at @/components/ecommerce/price, not at @/price.
import { Button } from "@/components/ui/button";
import { ProductCard } from "@/components/ecommerce/product-card";
import { Hero } from "@/components/sections/hero";
import { money, formatMoney } from "@/lib/money";
// Prices are Money — integer minor units with the currency attached,
// so a cart total cannot drift and a euro store cannot render dollars.
<ProductCard title="Country Sourdough" price={money(900, "USD")} />;Changing how it looks
Five tiers, least invasive first. Reach for the lowest one that works — the lower it is, the longer the component keeps receiving updates.
- 1. Brand token
Swap values — colors, --radius, --shadow-color, fonts. Every token-driven component re-skins at once. Squared vs rounded is one variable.
- 2. Component variant
Use the variant or size the component already ships. No new CSS, no new file.
- 3. className at the call site
cn() runs tailwind-merge, so a class you pass in beats the component's own.
- 4. Wrapper component
Re-export a wrapped version to set app-wide defaults without touching the original.
- 5. Own the copy
Edit the installed source. That file then diverges from the registry and stops tracking it — which is a legitimate choice, just a deliberate one.
Only the last one forks the file. Everything above it survives a re-install, and pnpm ui:check in your app will tell you which of your copies have drifted, and by how many versions.
Where to look
Three places, and they don't overlap: the catalog documents components, this site runs the pages, the harness proves the full-stack addons.
Page blocks
Full pages composed from the primitives and commerce components. Each one is live here and installable by name.
Every block, with the route it installs to, is on the blocks page.
Design tokens
The whole system reduces to these values. They are generated from themes/*.mjs into CSS variables, so everything below is drawn from the same source the components read — switch the theme in the header and every swatch re-skins live.
Primary
Surfaces
Semantic
Commerce
sale must read as the primary price; out-of-stock pairs with clear text — never color alone.
Chart accents
Typography
Named styles — use the utility class, not an ad-hoc text-* stack, so type stays consistent. A brand swaps in its own heading and body typefaces through the same token map.
Price styles
price$24.00price-lg$24.00price-sale + original$18.00$24.00unit / from$4.50Radius & shadow
Corner softness and shadow warmth are what separate handmade from clinical, and both are one value per brand — radius steps scale off --radius, shadows tint with --shadow-color.
Radius scale
rounded-smrounded-mdrounded-lgrounded-xlrounded-2xlrounded-3xl