Add Astro native component override support with ADR-008 named slots
Astro is a special case per ADR-008: it is both an adapter (routing, build integration) and has its own component format with native named slots. Unlike Next.js and Nuxt which need separate renderer packages (@refrakt-md/react, @refrakt-md/vue), Astro component overrides can be handled directly in packages/astro/ using Astro's built-in <slot name="..."> mechanism.
For interactive runes rendered inside Astro islands, the island's framework renderer (React, Svelte, or Vue) handles extraction — that is covered by WORK-123, WORK-124, and WORK-119 respectively. This work item covers static .astro component overrides only.
Acceptance Criteria
packages/astro/supports registering.astrocomponent overrides keyed bytypeofname- Renderer dispatches on
typeofattribute to select registered.astrocomponent overrides (falls back to identity-transformed HTML) - Uses
extractComponentInterfacefrom@refrakt-md/transformto partition children - Property values passed as Astro props (
Astro.props.prepTime, etc.) - Top-level refs passed as Astro named slots (
<slot name="headline" />,<slot name="ingredients" />) - Original
tagobject passed as prop alongside extracted props (hybrid per ADR-008 Option 4) - Component registry mechanism added to
@refrakt-md/astro(e.g.,registry.ts) - Integration hook wires up the registry so components are available at render time
- TypeScript compiles cleanly
- Test suite covers extraction, dispatch, and fallback rendering
Approach
Unlike React/Vue renderers which are recursive components, the Astro renderer operates at build time during SSR. The approach is:
- Component registry — export a
registrymap oftypeofname →.astrocomponent, similar to@refrakt-md/svelte's registry - Render phase — when rendering a node with a
typeofthat matches a registered component, useextractComponentInterfaceto partition children, then render the.astrocomponent with props and named slots - Fallback — unregistered runes render via identity-transformed HTML as today
Astro's native named slots make this particularly clean:
---
const { prepTime, difficulty } = Astro.props;
---
<article class="my-recipe">
<slot name="headline" />
<slot name="ingredients" />
<slot name="steps" />
</article>
The main complexity is integrating the component dispatch into Astro's rendering pipeline, which differs from Svelte/React/Vue's recursive component model.
References
- Framework-native component interface for rune overrides — Framework-native component interface for rune overrides (see Astro special case in Consequences)
- Implement framework-agnostic extraction logic for component interface — Framework-agnostic extraction logic (done)
- Update Svelte renderer to pass props and snippets to component overrides — Svelte renderer extraction (done, reference implementation)
- Create @refrakt-md/react renderer with ADR-008 component interface — React renderer (for island components)
- Create @refrakt-md/vue renderer with ADR-008 component interface — Vue renderer (for island components)
packages/astro/— Astro adapter (this package gets the additions)
Resolution
Completed: 2026-04-06
Branch: claude/implement-spec-030-F0LFn
What was done
RfRenderer.astro— recursive Astro component that dispatches ondata-runeto registered component overrides- Component overrides receive extracted properties as Astro props, named refs as native Astro named slots (
<Fragment slot="name" set:html={html} />), anonymous children as default slot, and originaltagas escape-hatch prop - Element overrides:
Table.astro(scrollable wrapper) andPre.astro(rf-codeblock structure) registry.ts— ComponentRegistry type + empty default, exported from index.ts- Package.json exports for
./RfRenderer.astroand./elements/*.astro - Removed stale
themeAdapterreference from integration hook (per ADR-009) - 8 tests covering registry, extraction pipeline, and dispatch logic
Notes
.astrocomponents shipped as source (not compiled), matching the existingBaseLayout.astropattern- Actual Astro component rendering can't be tested in vitest — tests cover the TypeScript extraction pipeline that
RfRenderer.astrodepends on - For interactive runes in Astro islands, the island's framework renderer (React/Vue/Svelte) handles extraction per WORK-123/124/119
Relationships
Implements
Related
History
- 59ded4aResolution recorded
- f262d7bsource+ADR-008,ADR-009
- c8b37c5statusdraft→done
- ☑ `packages/astro/` supports registering `.astro` component overrides keyed by `typeof` name
- ☑ Renderer dispatches on `typeof` attribute to select registered `.astro` component overrides (falls back to identity-transformed HTML)
- ☑ Uses `extractComponentInterface` from `@refrakt-md/transform` to partition children
- +7 more criteria
- 4cfe47cCreated (draft, medium, complex, astro, renderer, architecture)