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.
Use the Vue package documentation (opens new window) or Web Components package documentation (opens new window) for the options supported by the frontend you choose.
Prerequisites
- Formie on Craft with at least one published form
- Node.js and npm (or pnpm/yarn)
- Frontend Assets
Package Overview
| Package | npm | Use when |
|---|---|---|
@verbb/formie-vue | Vue 3 bindings | Your app is Vue or Nuxt |
@verbb/formie-web-components | Custom elements | You want framework-agnostic embeds, or Vue/React coexist on one page |
@verbb/formie-browser | Shared browser package | Required peer for both packages |
@verbb/formie-core | Form definition + state | Required for client-rendered mode |
Install pattern (Vue example):
npm install @verbb/formie-browser @verbb/formie-core @verbb/formie-vue vueImport 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
| Transport | Pros | Considerations |
|---|---|---|
| REST | Simple endpoint, easy local dev | Requires Formie REST routes enabled |
| GraphQL | Typed schema, single API surface | Needs 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:
- Vue starter (opens new window)
- Web Components starter (opens new window)
- Nuxt starter (opens new window)
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.