You are viewing beta documentation for Formie 4.x.
Developers

TipTap Extensions

You can add text styles or custom editor features to the rich-text editors used throughout the form builder. Matching server and browser definitions let Formie display the saved content consistently in the editor, previews, front-end pages and emails.

Formie does not register any project-specific extensions itself. The controls and TextStyle capabilities listed below are provided by Plugin Kit; your module or plugin can add to that shared schema through Formie's registration event.

  • Use a TextStyle definition for a visual setting with a fixed list of allowed values.
  • Use matching PHP and JavaScript extensions for custom nodes, semantic marks, node views, ProseMirror plugins, or other advanced behavior.

Registrations must be installed during application bootstrap, before the form builder creates an editor. Existing editor instances are not rebuilt dynamically.

Enable Built-in Text Styles

Font family, font size, text color, background color, line height, and small caps already use TipTap's textStyle mark. Enable their controls for a particular Formie rich-text field in config/formie/rich-text.json:

{
    "fields": {
        "content": {
            "buttons": [
                "font-family",
                "font-size",
                "bold",
                "italic",
                "small-caps",
                "text-color",
                "line-height",
                "link"
            ]
        }
    }
}

These controls use the official TipTap TextStyle extensions. Formie sends the same attributes to verbb/tiptap for server-side HTML rendering, so no custom registration is required for the built-in styles.

Enable Small Caps

Small caps is built in but is not added to existing toolbars automatically. Add small-caps to any relevant entry in config/formie/rich-text.json:

{
    "fields": {
        "content": {
            "buttons": ["bold", "italic", "small-caps", "link"]
        },
        "instructions": {
            "buttons": ["bold", "italic", "small-caps", "link"]
        }
    },
    "notifications": {
        "content": {
            "buttons": ["bold", "italic", "small-caps", "variableTag"]
        }
    }
}

The stored representation is a textStyle mark with fontVariantCaps: "small-caps". Formie and verbb/tiptap render it as font-variant-caps: small-caps in frontend and notification HTML.

Small caps is owned by Plugin Kit, but it is not a separate TipTap mark. It adds the constrained fontVariantCaps attribute to textStyle, allowing it to coexist with a font family, size, color, background color, and line height on the same text.

Declare a Safe Text Style Once

Listen for TiptapExtensions::EVENT_REGISTER_EXTENSIONS in your module or plugin init() method. A TextStyle definition is sent to the form builder as validated metadata and installed automatically on the client:

use verbb\formie\events\RegisterTiptapExtensionsEvent;
use verbb\formie\services\TiptapExtensions;
use verbb\formie\tiptap\TextStyleDefinition;
use yii\base\Event;

Event::on(
    TiptapExtensions::class,
    TiptapExtensions::EVENT_REGISTER_EXTENSIONS,
    function(RegisterTiptapExtensionsEvent $event): void {
        $event->registerTextStyle(
            new TextStyleDefinition(
                id: 'acme-uppercase',
                label: 'Uppercase',
                attribute: 'textTransform',
                cssProperty: 'text-transform',
                allowedValues: ['uppercase'],
                toolbarValue: 'uppercase',
            ),
        );
    },
);

Add acme-uppercase to the desired buttons configuration. Declarative styles are limited to Formie's allowlisted CSS properties and values. This prevents a project configuration or CP bootstrap value from becoming arbitrary CSS.

Register a Full Extension

Persisted custom nodes and marks require matching server and client extensions. Register the PHP half with the same stable ID used by the JavaScript half:

Event::on(
    TiptapExtensions::class,
    TiptapExtensions::EVENT_REGISTER_EXTENSIONS,
    function(RegisterTiptapExtensionsEvent $event): void {
        $event->registerExtension('acme/abbreviation', new AbbreviationMark());
    },
);

The JavaScript half must use Formie's bundled TipTap instance. Do not bundle a second copy of TipTap or ProseMirror. Formie exposes core and the ProseMirror model, state, and view modules on Craft.Formie.tiptap:

const register = ({ detail }) => {
    const { Mark } = detail.core;

    detail.registerTiptapExtension('acme/abbreviation', () => Mark.create({
        name: 'abbreviation',
        parseHTML: () => [{ tag: 'abbr' }],
        renderHTML: ({ HTMLAttributes }) => ['abbr', HTMLAttributes, 0],
    }));

    detail.registerTiptapControl('abbreviation', {
        label: 'Abbreviation',
        run: (editor) => editor.chain().focus().toggleMark('abbreviation').run(),
        isActive: (editor) => editor.isActive('abbreviation'),
    });
};

if (Craft.Formie?.tiptap) {
    register({ detail: Craft.Formie.tiptap });
} else {
    document.addEventListener('formie:tiptap:register', register, { once: true });
}

Add abbreviation to the toolbar configuration. The server registration ID is checked before the form builder mounts; a missing client half throws a clear error rather than allowing an editor with an incompatible schema to save.

Asset Loading

Ship the JavaScript registration in a Craft AssetBundle and depend on verbb\formie\web\assets\cp\TiptapAsset. This guarantees that the bridge and its bundled modules exist before your script runs. Register your bundle on the Formie form-builder CP route during your plugin or module bootstrap.

Client-only behavior extensions may omit the PHP registration when they cannot change stored content. Any node, mark, or attribute that can be persisted must be registered on both sides and should target both Plugin Kit document surfaces.

Formie uses Plugin Kit's shared extension registry. Register extensions through the Formie event above so they are available to its editors and rendering code.

For the underlying APIs and schema rules, see Plugin Kit's Extending TipTap (opens new window) guide, the verbb/tiptap PHP package, and TipTap's TextStyleKit documentation (opens new window).