Skip to content

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 add refreshes, 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 seeding lib/components-v3/.
  • Several primitives' index.ts reference non-existent siblings (avatar-group-count, item-footer/header/separator). Stripped with scripts/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 / Input carry 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