Storyblok
Search Storyblok's Documentation
  1. @storyblok/field-plugin

@storyblok/field-plugin

To bridge your field plugin application and the Visual Editor, Storyblok provides the @storyblok/field-plugin library. Storyblok also provides a command-line interface (CLI) for creating new field plugins from templates so that you do not need to integrate @storyblok/field-plugin yourself.

Please refer to the field plugins documentation for a comprehensive introduction to developing your first plugin.

Integrating @storyblok/field-plugin

To integrate @storyblok/field-plugin into a frontend framework, bootstrap your application with the --template js flag.

npx @storyblok/field-plugin-cli@latest --template js

The application's entry point is in src/main.js. Replace this code with the following:

const rootElement = document.createElement('div')
rootElement.id = 'app'
document.body.appendChild(rootElement)

This adds a new node to the body element, to which you can mount your application.

Next, run createFieldPlugin() as an effect. Your application is now listening to events from Storyblok's Visual Editor. As an argument, this function accepts a callback function that will be called whenever the state of the field plugin changes. This happens whenever the end-user edits the content, opens a modal, selects an asset, etc. A simple example with vanilla JavaScript may look like this:

import { createFieldPlugin } from '@storyblok/field-plugin'

// This button is the only element in this application
const buttonEl = document.createElement('button')
document.body.appendChild(buttonEl)

// Establish communication with the Visual Editor
createFieldPlugin({
  onUpdateState: (response) => {
    // Handle events from the Visual Editor by re-rendering the button element
    const content = typeof response.data.content === 'number' ? response.data.content : 0
    buttonEl.textContent = `Increment: ${content}`
    buttonEl.onclick = () => response.actions.setContent(content+ 1)
  }
})

createFieldPlugin() returns a cleanup function that removes all created side effects. Call this function when your application unmounts.

API Reference

createFieldPlugin() is a function that connects field plugins to the Storyblok Visual Editor. It accepts a callback function invoked with a FieldPluginResponse object whenever the state of the field plugin changes.

The function returns another function that can be used to clean up the event listeners that createFieldPlugin() added.

Parameter: callback: (response: FieldPluginResponse) => void: A callback function that is called whenever the state of the field plugin changes. The function is passed a FieldPluginResponse object as its only argument.

Return Value: () => void: A function that removes the event listeners added by createFieldPlugin().

FieldPluginResponse

FieldPluginResponse is an object that represents the current state of a field plugin.

Overview of properties

  • type: A string that indicates which overall state the field plugin is in. It can assume three values: loading (when the state is initially loaded and has not yet established communication with the Visual Editor), error (the plugin failed to load), and loaded (the plugin successfully loaded and is ready to use).
  • error: If FieldPluginResponse.type is error, the error property will contain an Error object instance. Otherwise, it is undefined.
  • data: If FieldPluginResponse.type is loaded, this property will contain the application state that the Visual Editor has shared with the field plugin. Otherwise, it is undefined.
  • actions: If FieldPluginResponse.type is loaded, this property will contain an object whose properties are functions that enable the field plugin application to interact with the Visual Editor. Otherwise, it is undefined.

FieldPluginResponse.data

FieldPluginResponse.data has the following properties:

  • blockUid: The UID of the block that the field plugin is part of.
  • content: The content of the field plugin that is part of the content.
  • isModalOpen: A boolean value that indicates whether the field plugin is embedded in a modal window.
  • interfaceLang: Specifies the language used in the Storyblok interface.
  • options: A dictionary/record of string key-value pairs containing the options set up for this field plugin in the block schema.
  • releaseId: Represents the numerical identifier for the currently selected release. To utilize this functionality, ensure the Releases App is enabled.
  • releases: Contains an array of objects providing details about all releases associated with the current story.
  • storyLang: The language of the story.
  • spaceId: The ID of the space.
  • userId: The user's ID.
  • story: The story that was initially loaded. If the user updates the story, this value will remain unchanged. To update this after the initial load, call FieldPluginResponse.actions.requestContext().
  • storyId: The ID of the story.
  • token: A draft access token to the Content Delivery API.
  • translatable: A boolean flag indicating whether the field plugin content is translatable.
  • isAIEnabled: A boolean flag indicating whether AI is enabled in the current space.
  • uid: The UID of the field plugin.

FieldPluginResponse.actions

FieldPluginResponse.actions has the following properties:

  • setContent: Updates the content of the field plugin. You can pass an object or a primitive value as an argument, and it will replace the old content. For example, setContent(3.14159).
  • setModalOpen: Opens/closes the modal window. For example, setModalOpen(true). Optional: If you want to resize the displayed modal, pass an object with the width and height as the second parameter. For example, setModalOpen(true, { width: '50%', height: '500px' }).
  • promptAI: (BETA) This action allows you to interact with the Storyblok AI endpoint, leveraging advanced capabilities to generate, modify, or translate content based on specific instructions.
  • selectAsset: Opens the asset selector. It returns a promise that is resolved when the user selects an asset. For example, selectAsset().then((filename) => console.log(filename)).
  • requestContext(): Updates the request.data.story property to the version of the story that is currently opened in the Visual Editor. That is the unsaved story version in the user's browser memory.
  • requestUserContext(): Returns a promise with a user object. The object contains the current logged user information isSpaceAdmin and permissions.

Manifest File for Field Plugins

The manifest file is a configuration that enhances the functionality of your field plugin. This JSON file, named field-plugin.config.json and located in your project's root folder, is optional but highly recommended.

The manifest file allows you to configure options for your field plugin. When developing your field plugin with the Sandbox, the options are applied by default. Also, the deploy command automatically applies the options in production. Therefore, you no longer need to configure the options manually.

Creating a Manifest File

If your field plugin doesn't already contain a manifest file, you can create one yourself at any time by following these steps:

  1. Begin by creating a field-plugin.config.json file in the root folder of your project.
  2. Populate the file with the following content:
{
  "options": []
}

The options list within this file should consist of key-value objects representing the essential options required for your field plugin to function correctly, along with their corresponding values. This is an example of how it should be structured:

{
  "options": [
    {
      "name": "myPluginInitialValue",
      "value": 100
    }
  ]
}

When this field plugin is added to a story, the option values are not shared. Only keys are configured for security reasons. However, during development, you can access these values using the Field Plugin Editor or Sandbox.

Now, you just need to access these options in your code like in the example below:

const plugin = useFieldPlugin()
 
console.log(plugin.data.options.myPluginInitialValue)

useFieldPlugin()

You can use useFieldPlugin() in Vue 3 and React projects.

import { useFieldPlugin } from '@storyblok/field-plugin/vue3';
// or
import { useFieldPlugin } from '@storyblok/field-plugin/react';
 
const plugin = useFieldPlugin({ validateContent: ... });
console.log(plugin); // { type, data, actions }
 
// later
plugin.actions.setContent(...);

Using useFieldPlugin() in multiple components

You can use useFieldPlugin() in multiple components. However, in each case, the createFieldPlugin() function will be executed, transitioning each plugin.type from loading to loaded. Therefore, you must verify the plugin.type in every component. Here is an example in React (the same applies to Vue):

function Parent() {
  return (
    <div>
      <Child1 />
      <Child2 />
    </div>
  );
}
 
function Child1() {
  const plugin = useFieldPlugin();
  return plugin.type === "loaded" && <div>Child1: {plugin.data}</div>;
}
 
function Child2() {
  const plugin = useFieldPlugin();
  return plugin.type === "loaded" && <div>Child2: {plugin.data}</div>;
}

This is fine. If you want to avoid checking if the plugin is loaded repeatedly, handle it in a parent component and pass the entire plugin object to the children.

import type { FieldPluginResponse } from "@storyblok/field-plugin";
type Plugin = FieldPluginResponse<MyContentType>;
 
function Parent() {
  const plugin = useFieldPlugin({ validateContent: undefined });
  return (
    plugin.type === "loaded" && (
      <div>
        <Child1 plugin={plugin} />
        <Child2 plugin={plugin} />
      </div>
    )
  );
}
 
function Child1({ plugin: Plugin }) {
  return <div>Child1: {plugin.data}</div>;
}
 
function Child2({ plugin: Plugin }) {
  return <div>Child2: {plugin.data}</div>;
}

Prompt AI (Beta)

The Prompt AI action enables you to leverage AI-powered capabilities for generating, modifying, and translating content directly within your Storyblok plugins. With this action, you can automate content creation, adjust tone, translate text, or simplify content to streamline your workflows.

Usage

To use the promptAI action, call it from the plugin actions. It accepts a payload that defines the action to perform and any additional parameters necessary for the operation.

Supported Actions

  • prompt: Generate new content based on an instruction.
  • complete: Finish incomplete text.
  • shorten: Condense content to a shorter version.
  • extend: Expand content with additional details.
  • rephrase: Rewrite content for clarity or style.
  • summarize: Provide a concise summary of content.
  • simplify: Make content simpler and easier to understand.
  • translate: Translate content into another language.
  • tldr: Create a brief summary ("Too Long; Didn't Read").
  • adjust-tone: Modify the tone of content (e.g., formal, casual).
  • emojify: Add emojis to the content for a playful style.
  • fix_spelling_and_grammar: Correct spelling and grammar issues.

Input Parameters

ParameterTypeRequiredDescription
actionstringYesThe action to perform. Must be one of the supported actions.
textstringYesThe input content for the AI to process.
basedOnCurrentStorybooleanNoWhether to consider the current story context during processing.
languagestringNoTarget language (required for translate action).
textLengthstringNoMaximum length of generated content (in characters or words).
tonestringNoDesired tone of content (required for adjust-tone action).
textLengthUnitstringNoUnit for length (e.g., characters or words).

Example

Below is an example of how to implement the promptAI action in a field plugin to generate some text:

await promptAIAction({
  action: 'prompt',
  text: 'Generate a title for my article',
  textLength: '160',
  basedOnCurrentStory: true,
});

Output

The promptAI action will return a response based on the action performed, such as generated text, translated content, or modified content.