The CWA is in heavy development
The CWA is still in alpha and not ready for production - some code and implementations are likely to change. If you would like to try out the CWA, please enjoy what we have provided and feel free to provide feedback, or get involved on GitHub.
Cwa Components

<CwaComponentGroup />

Render an ordered list of CMS-managed components within a named region of your layout, page, or component.

<CwaComponentGroup> is the primary building block of every CWA page. Place it inside any layout, page template, or component to create a named content region that admins can populate with components in the CMS.

<CwaComponentGroup reference="hero" :location="iri" />

Props

PropTypeRequiredDefaultDescription
referencestringYesName of the component group within this resource. Determines which ComponentGroup entity this region maps to.
locationstringYesIRI of the parent resource that owns this group (your layout, page, or component IRI).
allowed-componentsstring[] | nullNonullCollection endpoints of the component types admins may add to this group (e.g. ['/component/hero_banners', '/component/text_blocks']). All CWA component endpoints are prefixed with /component/. When set, the value is synced to the ComponentGroup entity in the API whenever an admin is signed in. null allows all types.

Basic Usage

Every layout, page template, and component that has editable content regions uses <CwaComponentGroup>. Pass the component's own iri prop as location:

<!-- app/cwa/pages/HomePage.vue -->
<template>
  <div>
    <CwaComponentGroup reference="hero" :location="iri" />
    <CwaComponentGroup reference="features" :location="iri" />
    <CwaComponentGroup reference="cta" :location="iri" />
  </div>
</template>

<script setup lang="ts">
import type { IriProp } from '@cwa/nuxt/runtime/composables'
defineProps<IriProp>()
</script>

The reference name is how the admin CMS identifies the region. It can be any string — keep it short and descriptive. Multiple groups on the same resource each need a unique reference.

In a Layout

<!-- app/cwa/layouts/PrimaryLayout.vue -->
<template>
  <div class="min-h-screen flex flex-col">
    <header>
      <CwaComponentGroup reference="navigation" :location="iri" />
    </header>

    <main class="flex-1">
      <!-- CWA renders the current page template here -->
      <slot />
    </main>

    <footer>
      <CwaComponentGroup reference="footer" :location="iri" />
    </footer>
  </div>
</template>

<script setup lang="ts">
import type { IriProp } from '@cwa/nuxt/runtime/composables'
defineProps<IriProp>()
</script>

In a Component

Components can themselves contain component groups, enabling nested composition:

<!-- app/cwa/components/TwoColumn/TwoColumn.vue -->
<template>
  <div class="grid grid-cols-2 gap-8">
    <div>
      <CwaComponentGroup reference="left" :location="iri" />
    </div>
    <div>
      <CwaComponentGroup reference="right" :location="iri" />
    </div>
  </div>
</template>

<script setup lang="ts">
import type { IriProp } from '@cwa/nuxt/runtime/composables'
defineProps<IriProp>()
</script>

How It Works

When <CwaComponentGroup> mounts it:

  1. Looks up the ComponentGroup entity for {reference}_{location IRI} in the resource store
  2. Reads the ordered list of ComponentPosition entities from that group
  3. Renders each ComponentPosition's component using the uiComponent field as the Vue component name
  4. In admin edit mode, wraps each component with selection handles and the add-component button

The group reference is stable — it identifies the same region across environments as long as the location IRI is the same.

Allowed Components

The API can restrict which component types are allowed in a specific group. The restriction is enforced in two places:

  • Write-side (admin UI) — components not in the allowed list are hidden from the "Add Component" dialog for that group.
  • Read-side (rendering)ComponentPosition entries whose resolved component type is not in allowedComponents are omitted from the API response entirely. This means a component that was positioned before allowedComponents was set (or whose type was later removed from the list) will silently not render.

Via the Vue prop — pass collection endpoint paths directly in the template. The module syncs this to the API entity whenever an admin is signed in, creating or updating the group as needed:

<CwaComponentGroup
  reference="hero"
  :location="iri"
  :allowed-components="['/component/hero_banners', '/component/video_blocks']"
/>

Via fixtures — pass an array of PHP FQCNs as the second argument to ->group():

$cwa->layout('primary', 'PrimaryLayout')
    ->group('hero', [App\Entity\HeroBanner::class, App\Entity\VideoBlock::class]);

Via REST API — send PHP FQCNs in allowedComponents when creating or updating a ComponentGroup. The API normalizes them to collection IRIs automatically:

{
  "allowedComponents": [
    "App\\Entity\\HeroBanner",
    "App\\Entity\\VideoBlock"
  ]
}

The normalizer converts these FQCNs to their /component/ collection endpoints (e.g. /component/hero_banners) before persisting.

The allowedComponents field is also returned when reading a Layout or Page with embedded component groups.