Custom fields
Custom fields provide the ability to extend the default set of field types and controls available in the page and content editors.
For example, suppose you want to add a field to the page editor that allows the user to select an emoji. Instead of creating an enum field and presenting emojis in a dropdown menu or thumbnail images, you can create a custom field type that renders the emojis directly.
Types of custom fields
Section titled βTypes of custom fieldsβThere are two types of custom fields:
- Inline Fields: Controls that are rendered directly in the form.
- Modal Fields: The form presents an βOpenβ button, from which a modal window opens with the custom control.
Inline fields
Section titled βInline fieldsβInline fields are rendered directly in the form. They are useful for simple controls that do not require a lot of space or that resemble standard form controls.
Modal fields
Section titled βModal fieldsβModal fields appear as an Open button within the form.
Clicking this button opens a modal in which the form control is rendered. Visual Editor automatically includes the label and functionality for closing the modal, although this can be customized.
These types of controls are useful for more complex controls that require more space or that would typically be used within a dialog window.
How custom fields work
Section titled βHow custom fields workβCustom fields are built either as an HTML file or the JavaScript bundle and presented in Visual Editor through an iframe. They can bring their own styling and use JavaScript to hook into the editor and data flow.
Field types vs control types
Section titled βField types vs control typesβCustom fields can be defined against any Visual Editor field type by specifying the control type and a path to the HTML file.
The custom field should then set the value of the field to match the expected format of the field type.
// stackbit.config.tsimport { ObjectModel } from "@stackbit/types";
export const HeroSection: ObjectModel = { name: "HeroSection", type: "object", fields: [ { type: "string", name: "title", label: "Heading" }, { type: "string", name: "emoji", controlType: "custom-inline-html", controlFilePath: ".stackbit/fields/emoji.html" } ]};
In the example above, the emoji
field is defined as a string
field type, but the controlType
is set to custom-inline-html
. This field is presented as an iframe using the contents of .stackbit/fields/emoji.html
(relative to the project root).
See the configuration reference for usage of controlType
and controlFilePath
.
Hook into the editor
Section titled βHook into the editorβWhen Visual Editor first loads, it looks for custom fields and injects a control.js
script into the HTML file. This controls when the script defined in the HTML file (noted below) fires.
The HTML file should include a script that hooks into the editorβs data flow. When the field first appears, Visual Editor looks to call a global stackbit.onUpdate()
function with an object of useful properties.
On the initial call, the init
property is set to true
, which can be used as a signal to attach event listeners to elements within the custom field.
Using the emoji example, each emoji could be presented as a button, and would update the fieldβs value when the button is clicked.
<script> window.stackbit = window.stackbit || {};
window.stackbit.onUpdate = options => { if (options.init) { const buttons = document.querySelectorAll("button"); buttons.forEach(button => button.addEventListener("click", event => { // Update the field's value ... }) ); } };</script>
See below for a more complete example.
Use JavaScript bundle
Section titled βUse JavaScript bundleβWhen controlType
is set to either custom-inline-script
or custom-modal-script
, the visual editor expects that value of
controlFilePath
is a link to the JavaScript bundle.
The visual editor will cache the code of the control, making it render faster. Also, React
and ReactDOM
is exposed within the iframe, which
decreases and optimizes the bundle size of the custom control.
Read more about controlFilePath
.
Best practices
Section titled βBest practicesβThis section provides some common practices for working with custom fields, before moving on to an example.
HTML file location
Section titled βHTML file locationβThe HTML file can be placed anywhere in the project. Because Visual Editor plays no role in production, we recommend that this be placed in a directory that isnβt published to the web and that doesnβt interfere with your application.
In the examples shared in this doc, weβre using a .stackbit
directory in the project root. This is typically where we recommend putting Visual Editor-specific files.
Add styles
Section titled βAdd stylesβIn most cases, a custom field is going to want to bring its own style for an enhanced editing experience. The best way to do this is either to write styles directly in the HTML file or to link to an external CSS file. See the next section for an example.
Use external assets
Section titled βUse external assetsβThe HTML file can import CSS and JavaScript files from anywhere in the project repository. However, itβs often easiest to place it in the same directory as the HTML file.
<!DOCTYPE html><html lang="en"> <head> <!-- ... --> <link rel="stylesheet" href="emoji.css" /> </head> <body> <!-- ... -->
<script src="emoji.js"></script> </body></html>