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.
Building Your Ui

Page Templates

How to create CWA page template components that define the content regions of a page using CwaComponentGroup and CwaPage.

A page template defines the structure of a page — the slots where admins add and manage content. The PHP Page entity's uiComponent field maps to your Vue file. For dynamic pages (isTemplate: true), many routes share one template but each route points to its own PageData record.

File Convention

app/cwa/pages/Primary.vue    →  CwaPagePrimary
app/cwa/pages/BlogDetail.vue →  CwaPageBlogDetail

The file name (without .vue) must match the uiComponent value on the Page entity.

Every Page Component Receives :iri

The module passes the page IRI as a prop. Declare it:

import type { IriProp } from '@cwa/nuxt/runtime/composables'
defineProps<IriProp>()

The iri prop is the IRI of the current Page entity. Pass it as the location to any CwaComponentGroup.

Minimal Page Template

<!-- app/cwa/pages/Primary.vue -->
<template>
    <main>
        <CwaComponentGroup reference="content" :location="iri" />
    </main>
</template>

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

Multiple Content Regions

A real page usually has distinct zones — hero, main body, sidebar:

<template>
    <div :class="uiClassNames">
        <section class="hero">
            <CwaComponentGroup reference="hero" :location="iri" />
        </section>

        <div class="grid lg:grid-cols-3 gap-8">
            <div class="lg:col-span-2">
                <CwaComponentGroup reference="main" :location="iri" />
            </div>
            <aside>
                <CwaComponentGroup reference="sidebar" :location="iri" />
            </aside>
        </div>
    </div>
</template>

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

const props = defineProps<IriProp>()
const cwa = useCwa()

const page = computed(() => cwa.resources.page.value)
const uiClassNames = computed(() => page.value?.data?.uiClassNames ?? '')
</script>

Dynamic Pages: Accessing Page Data

When the page is a template (isTemplate: true), cwa.resources.pageData contains the current record's data:

const cwa = useCwa()

const pageData = computed(() => cwa.resources.pageData.value)
const headline = computed(() => pageData.value?.data?.headline)
const createdAt = computed(() => pageData.value?.data?.createdAt)

The module automatically sets the <title> and <meta name="description"> from pageData.data.title and pageData.data.metaDescription. You don't need to call useHead for the basics.

Registering Pages

// nuxt.config.ts
cwa: {
    pages: {
        Primary: {
            name: 'Standard Page',
            classes: [
                { value: '', label: 'Default' },
                { value: 'full-width', label: 'Full Width' }
            ]
        },
        BlogDetail: {
            name: 'Blog Article',
            classes: []
        }
    }
}

Page Load State

const isPageLoading = computed(() => cwa.resources.isLoading.value)
const progress = computed(() => cwa.resources.pageLoadProgress.value)
// { total: 8, complete: 5, percent: 62.5, resources: [...IRIs] }

Use progress.percent to drive a loading bar if you need one.


Nested Pages

If your pages have a parent–child URL structure — events listing → event detail, blog → post, docs section → page — add <CwaPage /> wherever the child should render inside the parent template. It works like <NuxtPage /> but for CWA's depth-aware hierarchy.

See <CwaPage /> for complete working examples, the inject key reference, and configuration.