system
400.wtf

400.wtf / system / docs · docs/ADR/0012-vue-sfc-components-static-by-default.md

ADR-0012 — DS components are Vue SFCs, static by default

Status: Accepted (implemented 2026-10-10, DS-0/DS-1)

Context

The site is Astro; artifacts are Vue islands. A DS could author static components in Astro and interactive ones in Vue, but Astro components can’t render inside Vue islands. That rules out, for example, a DS Button inside the artifact config panel. React + shadcn was considered for speed. shadcn’s head start is a rounded-card SaaS look the brief explicitly rejects, and the artifacts are Vue.

Decision

Every DS component is a Vue SFC. Astro renders it to HTML with no client:* directive, shipping zero JS. Hydration is decided where a component is used, not by its file type. Headless behavior for complex widgets (select, dialog, slider, switch, visually-hidden) comes from Reka UI. Styling is always ours. Component styles live in @layer components so utilities can override them.

Consequences

  • One authoring model across static pages and islands, and the DS is usable outside Astro (e.g. a standalone black-hole demo).
  • Vue can’t render Astro’s <Image>, so media components take pre-resolved image data from the site.
  • Guard against accidental hydration: /system/* must render correctly with JS disabled (Playwright check, DS-4).