Skip to content
This repository was archived by the owner on Jun 28, 2026. It is now read-only.

Form: TypeScript doesn't know about the Form function validate #8591

Description

@ataylor32

Describe the bug

My project relies on server-side validation. I don't know how this is intended to be accomplished with the PrimeVue Forms library. Looking at the documentation, it seems like validation is intended to happen entirely on the client side. That being the case, the way I have accomplished server-side validation feels fairly kludgy. But, setting that aside, the fact remains that I should be able to use formRef.value.validate(); without TypeScript complaining. As it is now, running npm run type-check outputs this:

src/App.vue:16:19 - error TS2339: Property 'validate' does not exist on type '{ $props: FormProps & VNodeProps & AllowedComponentProps & ComponentCustomProps; $slots: FormSlots; $emit: ((e: "submit", event: FormSubmitEvent<...>) => void) & ((e: "reset", event: FormResetEvent) => void); }'.

16     formRef.value.validate()
                     ~~~~~~~~

The code works, it's just that it has a TypeScript error that I need to ignore with a @ts-expect-error comment.

Here is the full code:

<script setup lang="ts">
import { Form, FormField, type FormSubmitEvent } from '@primevue/forms'
import { ref, useTemplateRef, watch } from 'vue'
import Button from 'primevue/button'
import InputText from 'primevue/inputtext'
import Message from 'primevue/message'

const formRef = useTemplateRef('form')

const status = ref<'idle' | 'submitting' | 'success' | 'communicationError'>('idle')

const errorsFromServer = ref<Record<string, string[]>>({})

watch(errorsFromServer, () => {
  if (formRef.value) {
    formRef.value.validate()
  }
})

async function submitHandler(e: FormSubmitEvent) {
  status.value = 'submitting'
  errorsFromServer.value = {}

  let response: Response | undefined = undefined

  try {
    response = await fetch('https://wizard-world-api.herokuapp.com/Feedback', {
      method: 'post',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        entityId: e.values.entityId || '',
        feedbackType: e.values.feedbackType || '',
        feedback: e.values.feedback || '',
      }),
    })
  } catch (e) {} // eslint-disable-line @typescript-eslint/no-unused-vars

  if (response && [200, 400].includes(response.status)) {
    if (response.status === 200) {
      status.value = 'success'
    } else {
      const responseBody = await response.json()
      errorsFromServer.value = responseBody.errors
      status.value = 'idle'
    }
  } else {
    status.value = 'communicationError'
  }
}

const resolver = ({ values }: { values: Record<string, string | undefined> }) => {
  return {
    errors: errorsFromServer.value,
    values,
  }
}
</script>

<template>
  <h1>Feedback</h1>

  <Message v-if="status === 'success'" severity="success">
    Feedback submitted successfully!
  </Message>

  <template v-else>
    <Message v-if="status === 'communicationError'" severity="error">
      An unexpected error occurred communicating with the server. Maybe the server is down or maybe
      you are not connected to the Internet.
    </Message>

    <Form ref="form" :resolver :validate-on-value-update="false" @submit="submitHandler">
      <FormField v-slot="$field" name="entityId">
        <label for="entityId">Entity ID</label>
        <InputText id="entityId" type="text" aria-describedby="entityId_help" required />

        <Message id="entityId_help" size="small" severity="secondary" variant="simple">
          A valid entity ID is: 3fa85f64-5717-4562-b3fc-2c963f66afa6
        </Message>

        <Message v-if="$field.error" severity="error" size="small" variant="simple">
          {{ $field.error }}
        </Message>
      </FormField>

      <FormField v-slot="$field" name="feedbackType">
        <label for="feedbackType">Feedback Type</label>
        <InputText id="feedbackType" type="text" aria-describedby="feedbackType_help" required />

        <Message id="feedbackType_help" size="small" severity="secondary" variant="simple">
          A valid feedback type is: General
        </Message>

        <Message v-if="$field.error" severity="error" size="small" variant="simple">
          {{ $field.error }}
        </Message>
      </FormField>

      <FormField v-slot="$field" name="feedback">
        <label for="feedback">Feedback</label>
        <InputText id="feedback" type="text" required />

        <Message v-if="$field.error" severity="error" size="small" variant="simple">
          {{ $field.error }}
        </Message>
      </FormField>

      <Button type="submit" label="Submit" :loading="status === 'submitting'" />
    </Form>
  </template>
</template>

Pull Request Link

No response

Reason for not contributing a PR

  • Lack of time
  • Unsure how to implement the fix/feature
  • Difficulty understanding the codebase
  • Other

Other Reason

No response

Reproducer

https://stackblitz.com/edit/primevue-4-ts-vite-issue-template-csnodp

Environment

Ubuntu 24.04

Vue version

3.5.35

PrimeVue version

4.5.5

Node version

26.3.0

Browser(s)

No response

Steps to reproduce the behavior

Run npm run type-check

Expected behavior

It shouldn't produce any errors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Package: Formsname: @primevue/formsStatus: Pending ReviewIssue or pull request is being reviewed by Core Team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions