useCwaComponent
The recommended composable for all CWA display components. Wraps useCwaResource and adds a typed plugin system so collection, image, and custom behaviours can be composed together without nesting.
const props = defineProps<IriProp>()
const { resource, exposeMeta } = useCwaComponent(props)
defineExpose(exposeMeta)
Signature
useCwaComponent(
props: IriProp,
plugins?: CwaResourcePlugin[],
ops?: {
name?: string
styles?: {
multiple?: boolean
classes: Record<string, string[]>
}
manager?: {
disabled?: boolean
}
autoClass?: boolean // default true — auto-applies uiClassNames to the root element
}
)
props — pass the raw defineProps<IriProp>() result directly (no toRef needed).
plugins — optional array of plugin factory results (see below).
ops — same options as useCwaResource: style variants, UI variant name, manager opt-out.
Return values
const { resource, exposeMeta, $cwa, getCurrentStyleName, ...pluginReturns } = useCwaComponent(props)
| Return | Type | Purpose |
|---|---|---|
resource | ComputedRef<Resource | null | undefined> | Reactive resource ref — access data on .value?.data |
exposeMeta | object | Pass directly to defineExpose |
$cwa | CwaComposable | Auth, resources, UI state |
getCurrentStyleName | (data) => string | undefined | Read the currently selected style name |
uiClassNames | ComputedRef<string[] | undefined> | The active style classes — auto-applied to the root element by default |
...pluginReturns | merged object | All return values from provided plugins |
defineExpose(exposeMeta) is required — without it the admin manager cannot select this component.
Basic component
<template>
<div v-if="resource?.data">
<h2>{{ resource.data.title }}</h2>
</div>
</template>
<script setup lang="ts">
import type { IriProp } from '#cwa/composables/cwa-resource'
import { useCwaComponent } from '#imports'
const props = defineProps<IriProp>()
const { resource, exposeMeta } = useCwaComponent(props)
defineExpose(exposeMeta)
</script>
resource.value states:
undefined— loadingnull— not found- object — data available
Plugins
Plugins extend useCwaComponent with additional state and methods. Pass an array of plugin factory results as the second argument. Return values from all plugins are merged and destructured alongside the base returns.
withCollection()
For components backed by the built-in Collection API resource. Returns pagination state and navigation helpers.
import { useCwaComponent, withCollection } from '#imports'
const props = defineProps<IriProp>()
const {
resource,
exposeMeta,
collectionItems,
isLoadingCollection,
totalPages,
pageModel,
goToNextPage,
goToPreviousPage,
changePage,
resolveResourceLink,
} = useCwaComponent(props, [withCollection()])
defineExpose(exposeMeta)
Replaces the deprecated useCwaCollectionResource.
withImage(imageOps?)
For components backed by a PHP entity with #[Silverback\Uploadable]. Returns image URL, load state, and media object data.
import { useCwaComponent, withImage } from '#imports'
const props = defineProps<IriProp>()
const {
resource,
exposeMeta,
contentUrl,
displayMedia,
handleLoad,
loaded,
mediaObjects,
} = useCwaComponent(props, [withImage()])
defineExpose(exposeMeta)
Options:
| Option | Description |
|---|---|
imagineFilterName | Imagine filter to apply to the image URL |
imageRef | Template ref pointing to the <img> element (auto-created if omitted) |
fileProp | Name of the PHP entity property holding the file (default: file) |
Replaces the deprecated useCwaImageResource.
Combining plugins
Multiple plugins can be composed in a single call — something the old useCwaCollectionResource / useCwaImageResource pattern could not do:
const { resource, exposeMeta, collectionItems, contentUrl } = useCwaComponent(
props,
[withCollection(), withImage()]
)
defineExpose(exposeMeta)
Style variants
const { resource, exposeMeta, getCurrentStyleName } = useCwaComponent(props, [], {
styles: {
multiple: false,
classes: {
'Default': [],
'Filled': ['bg-blue-600', 'text-white', 'px-6', 'py-2', 'rounded-md'],
'Outlined': ['border', 'border-blue-600', 'text-blue-600', 'px-6', 'py-2'],
}
}
})
const currentStyleName = computed(() => {
if (!resource.value?.data) return undefined
return getCurrentStyleName(resource.value.data)
})
The style names appear in the admin "Style" selector. The selected classes are automatically applied to the component's root element — no :class binding needed.
Applying classes to an inner element
If you want the style classes on an inner element rather than the root, opt out of auto-apply and bind uiClassNames manually:
const { resource, exposeMeta, uiClassNames } = useCwaComponent(props, [], {
autoClass: false,
styles: { ... }
})
<template>
<div>
<a :class="uiClassNames">{{ resource?.data?.label }}</a>
</div>
</template>
Writing a custom plugin
A plugin is a function that receives { iri, resource, $cwa } and returns any object:
import type { CwaResourcePlugin } from '#cwa/composables/cwa-component'
const withWordCount = (): CwaResourcePlugin<{ wordCount: ComputedRef<number> }> => {
return ({ resource }) => {
const wordCount = computed(() => {
const body = resource.value?.data?.body ?? ''
return body.split(/\s+/).filter(Boolean).length
})
return { wordCount }
}
}
// Usage
const { resource, exposeMeta, wordCount } = useCwaComponent(props, [withWordCount()])