Server-Rendered

Styling ​

If you are in client-rendered forms, Vue owns the visible UI and you should style your own components directly.

Import the Browser CSS ​

Server-rendered forms use the browser package theme:

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

Or split the layers if your app needs that separation:

ts
import '@verbb/formie-browser/css/formie-base.css';
import '@verbb/formie-browser/css/formie-theme.css';

Use Tokens First ​

Start with the --formie-* CSS variables provided by the browser package to change colours, spacing and other styles.

Use Browser → CSS variables for the full token reference.

Scope those tokens on a wrapper around the form:

css
.contact-form-shell {
  --formie-color-primary: #0f766e;
  --formie-color-primary-hover: #115e59;
  --formie-button-border-radius: 999px;
}
vue
<template>
  <div class="contact-form-shell">
    <FormieForm
      transport="rest"
      endpoint="https://formie.test"
      form-handle="contactForm"
    />
  </div>
</template>

When you use useFormieHtml(), wrap the element bound to rootRef the same way.

Use themeConfig Second ​

If tokens are not enough, themeConfig lets you inject classes, attributes, and reset behaviour into the shipped server-rendered theme.

Browser-supplied theme config can set classes, supported attributes and CSS custom properties. To change tags, add HTML or attach event handlers, use server-side configuration or template overrides.

Add Classes and Attributes ​

Use this when you want to keep Formie's HTML structure but attach app-owned classes or data attributes at known theme hooks:

vue
<script setup lang="ts">
import { FormieForm } from '@verbb/formie-vue';
</script>

<template>
  <FormieForm
    transport="rest"
    endpoint="https://formie.test"
    form-handle="contactForm"
    theme="formie"
    :theme-config="{
      field: {
        attributes: {
          class: ['starter-field', 'starter-field--spaced'],
          'data-scenario': 'custom-styling',
        },
      },
      fieldLabel: {
        attributes: {
          class: ['starter-label'],
        },
      },
      fieldControl: {
        attributes: {
          class: ['starter-control'],
        },
      },
    }"
  />
</template>

Reset Selected Theme Layers ​

Use this when you want Formie to keep the HTML structure, but you want to rebuild specific visual layers yourself:

vue
<script setup lang="ts">
import { FormieForm } from '@verbb/formie-vue';
</script>

<template>
  <FormieForm
    transport="rest"
    endpoint="https://formie.test"
    form-handle="contactForm"
    theme="formie"
    :theme-config="{
      field: {
        resetClass: true,
        attributes: {
          class: ['rounded-2xl', 'border', 'p-4'],
        },
      },
      fieldLabel: {
        resetClass: true,
        attributes: {
          class: ['text-xs', 'font-semibold', 'uppercase'],
        },
      },
    }"
  />
</template>

Compose with Tokens ​

themeConfig and CSS tokens work well together. Use themeConfig for structural hooks, then use CSS for the visual system:

vue
<script setup lang="ts">
import { FormieForm } from '@verbb/formie-vue';
</script>

<template>
  <div class="marketing-shell">
    <FormieForm
      transport="rest"
      endpoint="https://formie.test"
      form-handle="contactForm"
      theme="formie"
      :theme-config="{
        field: {
          attributes: {
            class: ['marketing-field'],
          },
        },
        fieldLabel: {
          attributes: {
            class: ['marketing-label'],
          },
        },
      }"
    />
  </div>
</template>
css
.marketing-shell {
  --formie-color-primary: #0f766e;
  --formie-button-border-radius: 999px;
}

.marketing-field {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8);
}

Use CSS Third ​

If tokens are not enough, add targeted CSS against the shipped server-rendered markup.

The safe rule is:

  1. tokens first
  2. themeConfig second
  3. targeted CSS third
  4. structural replacement only when you are leaving server-rendered forms behind

If you find yourself fighting the shipped HTML structure with heavier CSS, that is usually a sign the problem belongs in client-rendered forms instead.

Last updated: Oct 8, 2026, 10:37 AM