useCwaFileField
useCwaFileField resolves one uploadable file field on a component backed by a PHP entity with #[Silverback\Uploadable]. It returns the display media, its content URL, and load state for that field. Because you name the field at the call site, one component can wire several file fields without them colliding.
It's the standalone form of the withFile() plugin — the same resolver under the hood, called directly instead of through useCwaComponent's plugin array.
useCwaImageResource (removed). The file APIs handle any uploadable file, not just images — imagineFilterName is an image-specific convenience.import { useCwaFileField } from '#imports'
import type { IriProp } from '#cwa/composables/cwa-resource'
const props = defineProps<IriProp>()
const { contentUrl, displayMedia, handleLoad, loaded } = useCwaFileField(props, {
imagineFilterName: 'thumbnail'
})
Signature
useCwaFileField(
props: IriProp, // your component's props (with `iri`)
fileOps?: {
fileProp?: string // the PHP #[UploadableField] property (default: 'file')
imagineFilterName?: string // Imagine filter variant to surface as displayMedia
imageRef?: ShallowRef // template ref for load detection (default: useTemplateRef(fileProp))
}
)
- Pass
propsdirectly — no need totoReftheiri; the composable resolves the resource itself. fileProp— which uploadable field to read. Defaults to'file', and also becomes the default template-ref name used to detect when an<img>has already loaded.imagineFilterName— the LiipImagineBundle filter to surface asdisplayMedia/contentUrl(e.g.'thumbnail','hero'). Omit for the original uploaded file.
Return values
| Return | Type | Purpose |
|---|---|---|
contentUrl | ComputedRef<string | undefined> | URL of the (optionally filtered) file |
displayMedia | ComputedRef<MediaFile | undefined> | The media object to display — has contentUrl, mimeType, width, height; undefined until available |
handleLoad | () => void | Call on the <img>'s @load event |
loaded | Ref<boolean> | true once handleLoad() fires |
Example
<template>
<NuxtImg
v-if="displayMedia"
ref="file"
:src="contentUrl"
:width="displayMedia.width"
:height="displayMedia.height"
@load="handleLoad"
/>
<div v-else class="skeleton h-48 w-full bg-gray-200 animate-pulse" />
</template>
<script setup lang="ts">
import { useCwaFileField } from '#imports'
import type { IriProp } from '#cwa/composables/cwa-resource'
const props = defineProps<IriProp>()
const { contentUrl, displayMedia, handleLoad } = useCwaFileField(props, { imagineFilterName: 'thumbnail' })
</script>
The ref="file" matches the default fileProp, letting the composable detect an already-cached image on mount. displayMedia stays undefined until the media exists, keeping the skeleton visible.
Multiple file fields
Call it once per field, naming each with fileProp:
const hero = useCwaFileField(props, { fileProp: 'heroImage' })
const thumb = useCwaFileField(props, { fileProp: 'thumbnail' })
// hero.contentUrl, thumb.contentUrl, …
If you're already calling useCwaComponent, prefer the plugin form — useCwaComponent(props, [withFile({ fileProp: 'heroImage' }), withFile({ fileProp: 'thumbnail' })]) exposes the same data under a files map.