You are viewing beta documentation for Formie 4.x.
Frontend & Headless

Vue and Web Components starter walkthrough

Formie ships first-class packages for Vue and Web Components alongside React. This walkthrough covers the same four integration stories — server-rendered HTML vs client-rendered UI, REST vs GraphQL — using the official starters as the reference implementation.

Prerequisites

  • Formie on Craft with at least one published form
  • Node.js and npm (or pnpm/yarn)
  • Frontend Assets

Package overview

PackagenpmUse when
@verbb/formie-vueVue 3 bindingsYour app is Vue or Nuxt
@verbb/formie-web-componentsCustom elementsYou want framework-agnostic embeds, or Vue/React coexist on one page
@verbb/formie-browserShared browser packageRequired peer for both packages
@verbb/formie-coreForm definition + stateRequired for client-rendered mode

Install pattern (Vue example):

npm install @verbb/formie-browser @verbb/formie-core @verbb/formie-vue vue

Import CSS once:

import '@verbb/formie-browser/css/formie.css';

Vue — server-rendered form

The <FormieForm /> component mirrors the React API. Formie loads the payload, mounts HTML, and owns browser behaviour.

<script setup>
import { FormieForm } from '@verbb/formie-vue';
import '@verbb/formie-browser/css/formie.css';
</script>

<template>
    <FormieForm
        transport="rest"
        endpoint="https://your-craft-site.test"
        form-handle="contactForm"
        theme="formie"
        @submit-success="(result) => console.log(result)"
    />
</template>

Props use kebab-case in templates (form-handle, site-id, static-cache). For GraphQL, set transport="graphql" and point endpoint at your GraphQL URL.

Pre-fetched payload

When your app already has the bootstrap payload:

<FormieForm :source="{ payload }" />

Vue — client-rendered form

Use <FormieClientForm /> when you want Vue components for each field:

<script setup>
import { FormieClientForm } from '@verbb/formie-vue';
</script>

<template>
    <FormieClientForm
        transport="graphql"
        endpoint="https://your-craft-site.test/api"
        form-handle="contactForm"
        :components="{
            Field({ field, children, errors }) {
                return h('div', { class: 'field' }, [
                    h('label', field.label),
                    children,
                    ...errors.map((e) => h('p', { class: 'error' }, e)),
                ]);
            },
        }"
    />
</template>

Composable helpers (useFormie, useFormieField, useFormiePage) match the React hooks for custom layouts.

Nuxt

Start from the Nuxt starter (opens new window). It demonstrates:

  • Server-side payload fetching in a route loader
  • Client-only mounting for browser-only APIs (captchas, file uploads)
  • REST and GraphQL transport switching via environment variables

For Nuxt 3+, wrap <FormieForm /> in <ClientOnly> when the page is statically generated and token refresh must run in the browser.

Web Components — drop-in embed

Web Components work anywhere you can add a script tag — static HTML, WordPress, legacy PHP, or inside Vue/React without a framework binding layer.

<link rel="stylesheet" href="/path/to/formie.css">

<formie-form
    transport="rest"
    endpoint="https://your-craft-site.test"
    form-handle="contactForm"
></formie-form>

<script type="module">
    import '@verbb/formie-web-components';
</script>

Register the custom element once; then use <formie-form> or <formie-client-form> in markup.

Client-rendered custom element

For app-owned rendering via slots:

<formie-client-form
    transport="graphql"
    endpoint="https://your-craft-site.test/api"
    form-handle="contactForm"
></formie-client-form>

Listen for events on the element:

const form = document.querySelector('formie-form');

form?.addEventListener('formie:submit:result', (event) => {
    console.log(event.detail);
});

Event names match the browser package DOM events (formie:submit:result, formie:page:navigate:after, and so on).

Choosing REST vs GraphQL

TransportProsConsiderations
RESTSimple endpoint, easy local devRequires Formie REST routes enabled
GraphQLTyped schema, single API surfaceNeeds public schema scopes configured

Both transports use the same session token model. Bootstrap via formieClientForm, submit via submitFormieClientForm. See GraphQL submission flow end-to-end.

Static caching

Pass static-cache attributes on the custom element or props on Vue components:

<FormieForm
    transport="rest"
    endpoint="https://your-craft-site.test"
    form-handle="contactForm"
    :static-cache="true"
    :refresh-tokens="true"
/>
<formie-form
    transport="rest"
    endpoint="https://your-craft-site.test"
    form-handle="contactForm"
    static-cache
    refresh-tokens
></formie-form>

See Cached forms in production.

Starter repos

Clone and run the official starters — they are the canonical review surface for each package:

Each starter includes working examples for HTML mode, component mode, REST, and GraphQL. Use them as copy-paste references before building from the package README alone.