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

useCwaFormRepeated

Bind a Symfony RepeatedType field (e.g. new password + confirmation) with cross-field validation.

useCwaFormRepeated wraps two useCwaFormInput instances for a Symfony RepeatedType field. Each side validates with the sibling's current value so the API can check that both entries match.

const { first, second } = useCwaFormRepeated(iri, 'form_name[fieldName]')

Parameters

ParameterTypeDescription
iriRef<string | undefined>IRI of the Form component resource
fullNamestringfull_name of the RepeatedType field (e.g. registration[plainPassword])

Return value

Returns { first, second } — each has the same shape as a useCwaFormInput return value:

PropertyTypeDescription
valueRef<string>Field value; bind with v-model="field.value.value"
varsComputedRefField vars from the API (label, required, etc.)
errorsComputedRef<string[]>Field-level errors (see pair-mismatch note below)
validComputedRef<null | boolean>null until both sub-fields have a value; then reads the parent RepeatedType node's validity
displayErrorsComputedRef<boolean>false until both fields have been blurred at least once (see below)
onBlur() => voidCall on the input's blur event
onInput() => voidDebounced; triggers cross-field validation
validate(extraData?) => Promise<void>Explicit validate (PATCH forms only)

Error display gate

displayErrors is false until both first and second have each been blurred at least once. This prevents surfacing a mismatch error on the second field the moment the user focuses the first — both fields must be visited before any pair-level error is shown.

Cross-field validation

onInput and onBlur are overridden to pass the sibling's current value as extraData when it is non-empty. This lets the API validate that both entries match without requiring a full form submit. If the sibling field is still empty, no extraData is sent.

Pair-mismatch errors

Symfony attaches pair-mismatch errors to [first]. When the mismatch is detected after the user typed in the second field, the composable redirects those errors to second.errors so the message appears next to the field the user most recently edited.

Example

<script setup lang="ts">
const props = defineProps<{ iri: string }>()
const iriRef = toRef(props, 'iri')
const password = useCwaFormRepeated(iriRef, 'registration[plainPassword]')
</script>

<template>
  <UFormField
    :label="password.first.vars.value?.label || 'New Password'"
    :error="password.first.displayErrors.value ? password.first.errors.value[0] : undefined"
  >
    <UInput
      v-model="password.first.value.value"
      type="password"
      autocomplete="new-password"
      @blur="password.first.onBlur"
      @input="password.first.onInput"
    />
  </UFormField>

  <UFormField
    :label="password.second.vars.value?.label || 'Confirm Password'"
    :error="password.second.displayErrors.value ? password.second.errors.value[0] : undefined"
  >
    <UInput
      v-model="password.second.value.value"
      type="password"
      autocomplete="new-password"
      @blur="password.second.onBlur"
      @input="password.second.onInput"
    />
  </UFormField>
</template>

Notes

  • Internally maps to {fullName}[first] and {fullName}[second] — these match Symfony's RepeatedType child names
  • Each side registers its own full_name in the form store via useCwaFormInputuseCwaForm.unregisteredFieldErrors will not include them
  • See the Forms guide for full context