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.
DraftComponent

useCwaFormInput

Bind a single Symfony form field to a reactive value, validate on input, and control when errors are displayed.

useCwaFormInput binds a single field inside a Form component to a reactive value and handles per-field validation, error display, and value synchronisation with the shared form store.

const { value, vars, errors, valid, displayErrors, onBlur, validate, onInput } = useCwaFormInput(iri, fullName)

Parameters

ParameterTypeDescription
iriRef<string | undefined>IRI of the Form component resource
fullNamestringSymfony field full_name (e.g. contact_form[name])
opts{ blurTrigger?: Ref<boolean> }Optional. When blurTrigger is given it replaces this field's own blur state as the error-display trigger — this is how useCwaFormRepeated gates both halves of a pair on a shared signal

Return value

PropertyTypeDescription
valueRef<any>Reactive local value — bind to your <input> with v-model
varsComputedRefFull field vars from the API (label, attr, errors, valid, etc.)
errorsComputedRef<string[]>Field-level error messages from the API
validComputedRef<boolean | null>true = valid, false = invalid, null = not yet evaluated
validatingRef<boolean>true while a validation PATCH for this field is in flight — bind to a trailing spinner
displayErrorsComputedRef<boolean>Whether errors should be shown — see below
onBlur() => voidCall on @blur to enable error display after the user leaves the field
validate(extraData?) => Promise<void>Trigger PATCH validation immediately
onInput() => voidDebounced (300 ms) wrapper around validate — call on @input

displayErrors

Errors should be displayed when any of the following is true:

  • The user has blurred the field (onBlur was called)
  • The field was previously valid and has since become invalid (regression)
  • The form has been submitted and failed (isSubmitAttempted is true for this IRI)

Errors are always hidden while validating is true, so a stale message doesn't flash during revalidation.

Bind it to a conditional wrapper around your error list so errors only surface at the right moment.

validate()

Sends the current field values to the form's {iri}/submit endpoint via PATCH so the API can validate them and return per-field errors. The store is updated automatically, and errors / valid react accordingly.

This happens for every form — the form's own method only controls the final submit(). The API treats a PATCH to /submit as a partial submit, so no data is persisted and no success event fires.

The API exposes a realtime_validate_disabled form option (set on UserLoginType and PasswordUpdateType) that surfaces in the root form vars, but the module does not currently read it — live validation runs regardless. Skip @input/onInput on a field if you don't want it.

Field full_name

Symfony serialises form fields using their full_name, which follows the pattern form_name[field_name] (or form_name[child][field_name] for nested fields). The value comes from vars.value.full_name in the form resource response.

Value lifecycle

  • Initialised from vars.value (the API's current value for this field)
  • Resets to the API value when iri changes (e.g. navigating between resources)
  • Synced into $cwa.forms.fieldValues so useCwaForm.submit() can read all fields at once
  • Cleared from the store on component unmount

Example

<script setup lang="ts">
const props = defineProps<{ iri: string; fullName: string }>()
const iriRef = toRef(props, 'iri')

const { value, vars, errors, displayErrors, onBlur, onInput } = useCwaFormInput(iriRef, props.fullName)
</script>

<template>
  <div>
    <label :for="props.fullName">{{ vars?.label }}</label>

    <input
      :id="props.fullName"
      v-model="value"
      v-bind="vars?.attr"
      @blur="onBlur"
      @input="onInput"
    />

    <ul v-if="displayErrors && errors.length">
      <li v-for="error in errors" :key="error" class="text-red-500">
        {{ error }}
      </li>
    </ul>
  </div>
</template>

Notes

  • Each field component should call useCwaFormInput with its own fullName — the composable registers itself in the shared store and cleans up on unmount
  • onInput is a 300 ms debounce so rapid typing doesn't flood the API with validation requests; call validate() directly if you need immediate validation
  • Extra data can be passed to validate(extraData) — it is merged into the PATCH body, useful when validation of one field depends on another's current value