ADR-0001 — Component library foundation: fulldev/ui¶
Status: Accepted Date: 2026-05-03 Deciders: Cathal Dempsey Consulted: outside Claude analysis (template-vs-library framing, training-data bias, EmDash content-shape concerns)
Context¶
The FCR replatform pipeline targets ~1800 sites (98% Wix, per the
2026-05-03 portfolio survey). Phase 4 of the v3 pipeline is "assemble" —
the deterministic step that takes matcher output and emits Astro
components. To date, components have been hand-authored in
components/src/components/ and the assembler emits them with extracted
props. This works but is bespoke per pattern and doesn't scale to the long
tail of Wix variations or to higher-tier client redesigns.
The decision: pick a foundational Astro component library to seed
lib/components-v3/ (a future canonical library), so matchers target a
known component API and new sites compose at the section level rather
than reinventing primitives.
Constraints¶
- No upstream runtime dependency. 1800 sites can't be subject to template churn (e.g. AstroWind 2.0 is in flight and not backwards compatible). Whatever is chosen must be copy-into-repo, fully owned.
- Props-first API. Matchers emit JSON
(
{ heading, subtext, image, ctas }). Components must accept that as props, not require slot wrapping or string-template assembly. - MIT or similar permissive licence. Required for redistribution as part of paid client deliverables.
- Tailwind-friendly. The stack is already Astro + Tailwind.
- Variant breadth. Wix sites vary considerably in section style (image-led hero, slideshow hero, video bg, split layouts, etc.). The more variants ship out of the box, the fewer we need to author.
Decision¶
Use fulldev/ui (https://ui.full.dev) as the foundation for the FCR
component library. Components are pulled into the repo via the shadcn
registry (npx shadcn@latest add @fulldev/<name>), become local files we
own, and the upstream registry is irrelevant after install — no runtime
dependency.
The matcher's output becomes the input to fulldev block components
(hero-1 through hero-13, features-1 through features-6, etc.).
When fulldev doesn't ship a needed pattern (e.g. no plain centered CTA
without testimonial), fork the closest variant into a custom block (e.g.
cta-wcp.astro) and add it to the library.
Alternatives considered¶
AstroWind (onwidget/astrowind)¶
MIT, most-starred Astro theme 2022/23/24. Ships Hero/Features/FAQs/ Testimonials/CTA/Contact and most patterns we need. Rejected as foundation:
- 2.0 in flight, not backwards compatible. With ~1800 sites either pinning a frozen version or migrating, neither is acceptable.
- Slot-heavy API (
<Fragment slot="title">) requires string-template wrapping in the assembler. Matcher output (a JSON object) doesn't drop in cleanly without an adapter pass. - Less variant breadth: 1–3 variants per pattern vs. fulldev's 6–13.
- Heavy LLM training-data presence (most-starred 3 years running). LLM enthusiasm for it reflects training-data bias, not architectural fit.
Retained as a fallback reference. When fulldev doesn't ship a needed pattern, copy AstroWind's widget into our library (MIT permits this) and adapt to fulldev's primitive set. AstroWind is reference-only — never pinned.
bejamas/ui (bejamas/ui)¶
MIT, primitives-only (Button, Card, Input, Accordion, Sheet, Sidebar, NavigationMenu, etc. — ~30–40 components). Not a candidate at the section-library level since it ships zero hero/features/CTA/footer blocks; competing it on "which section library hits Wix-site fidelity" is a category error.
Open question, tracked separately (ADR-0002): is bejamas's primitive
layer a better foundation for v3 bespoke-section work than fulldev's
primitives? The concern is whether fulldev's Button, Card, Input
carry an aesthetic fingerprint (border-radius, hover state, focus ring)
that leaks into every FCR site regardless of token swaps. Settle with a
short primitive-neutrality test (same primitives, three brand palettes,
side-by-side eyeball). Not blocking the foundation decision.
Bespoke from scratch (current v2/v3)¶
The existing components/src/components/ lives on. Matchers stay (they
encode what each Wix section means); only the rendering target shifts
to fulldev components. The bespoke baseline at wcp-assembled.pages.dev
remains a working comparison and a fallback for sites where fulldev
variants don't fit at all.
Consequences¶
Positive¶
- Block variant breadth (13 hero, 6 content, 8 CTA) gives matchers room to pick close fits without authoring custom variants.
- Props-first API: matcher output → component props is a flat object map. The Portable Text → component-props adapter the EmDash workflow needs is essentially zero work for fulldev blocks.
- shadcn-registry install model: components arrive in our repo as files
we own; future updates are
npx shadcn addrefreshes, not template forks. - Larger primitive base (35 primitives + 77 blocks) means the long tail of unique Wix patterns is more likely to compose from existing pieces.
- Active maintenance: latest release v0.8.3 on 2026-03-24, last commit 2026-04-18.
Negative / risks¶
- Tailwind v4 commitment. Pins us to v4+. Acceptable.
- shadcn 4.x CLI install path crashes on the fulldev install (parser
error during file transformation). Bypassed with
pilots/wcp-fulldev/scripts/install-fulldev.cjs(50 LOC manual registry pull). Will need this script (or a fix) when seedinglib/components-v3/. - Several primitives'
index.tsreference non-existent siblings (avatar-group-count, item-footer/header/separator). Stripped withscripts/fix-broken-exports.cjs. Same fix-up required when seeding the canonical library. - No "plain centered CTA" variant — every fulldev CTA forces a
testimonial block. First fork already needed (
cta-wcp.astro). Track the rate of forks-per-site as the FCR pipeline scales; if >20% of sites need at least one fork, the variant breadth is overstated. - Aesthetic-fingerprint risk in primitives — if fulldev's
Button/Card/Inputcarry a recognisable look that token swaps can't override, every FCR site will share a visual DNA. Untested. ADR-0002 resolves. - No content-collections integration out of the box. Either fulldev or bejamas, an EmDash Portable Text → component-props adapter must be written. This is property of EmDash, not fulldev.
When to revisit¶
- ADR-0002 (primitive neutrality) finds fulldev primitives leak strong aesthetic across brand palettes → revisit the primitive layer (not the block layer).
- bejamas/ui ships sections at variant breadth comparable to fulldev → revisit the block layer.
- fulldev/ui becomes unmaintained (>6 months no commit, no release) → fork upstream, then keep going.
- Forks-per-site rate exceeds 20% across the next 5 ingested sites → revisit whether the matcher should target a different library or whether we should write more custom variants up front.
References¶
- Pilot:
pilots/wcp-fulldev/→ https://master.wcp-fulldev.pages.dev (noindex) - Comparison:
pilots/wcp-astrowind/→ https://master.wcp-astrowind.pages.dev (noindex) - Bespoke baseline: https://wcp-assembled.pages.dev
- Memory:
feedback_fulldev_chosen.md,feedback_component_library_strategy.md,feedback_visual_variation_as_props.md,reference_astro_component_kits.md - Survey informing the constraint:
survey/results.json(1597 sites),survey/histogram.csv