Visual CMS

Drag-and-drop visual editor and headless CMS for any tech stack

Theme Studio for Shopify

Build and optimize your Shopify-hosted storefront, no coding required



Get StartedLogin








Made in Builder

Extending Builder with Plugins

While we put a lot of effort into making Builder come with great defaults, you can customize nearly every part of the CMS and editor using custom React code with our plugin system.

Possible examples include an image management plugin, a plugin to integrate with Shopify, or a plugin to customize the look and feel of the Builder editor.

👉Tip: If you want to dive in head first and start coding, jump over to our examples in Github to get hacking

What can you modify

With Builder plugins, there are two main customization areas. One if registering custom types, which are used in many places in the Builder UIs, and the other is to modify the editor UI itself

Custom type editors

Custom editor plugins allow you to register custom field types for your Builder model custom fields and inputs for your custom components, custom targeting or symbols.

To create a custom editor, you will need to build a react component that takes a value prop and an onChange prop. Then within your custom editor component you simply call the passed in onChange function when the value is updated (example). The value you set can be any type serializable to JSON (e.g. string, number, null, array, object, etc) and be as deeply nested as you need.

You also have the option of passing data into your plugin when registering it as an input type. This is useful if you have things like api keys or settings that you want to control in your own codebase, but want to be able to pass into the plugin whenever it is used. To do this, use the options property when registering an input for a component. See this example for more details, as well as the code example below.

Plugins execute inside the Builder web application, so they need to be developed separately from your web application. Take a look at the sample code below for a simplified example of how to build and use a custom editor. For a more detailed and in depth example, see the example plugin for instructions on how to build, deploy, and connect your plugin to your account.

Custom Editor


import { Builder } from '';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';

// Example of using the react-quill library to create a new
// rich text editor for use in the Builder editor
function RichTextEditor(props) {
  // Pass in arbitrary options when registering 
  // this editor as an input for a component
  const { theme } = props.field.options;

  return (
      theme={theme ? useTheme :  'snow'}

  name: 'myRichText',
  component: RichTextEditor,

Modifying the editor and CMS

Below are some of the possible parts of the editor that you are able to modify via Builder.register(<some-key>) .

👉Tip: See our campaign plugin example for a kitchen sink app highlighting nearly all of the features below



Make an app-wide tab that displays and edits content in unique ways using our read and write APIs

E.g. make a content calendar that allows you to view your scheduled content on a calendar showing when content will go live when, and allow the user to drag to reschedule

import { Builder } from '';

function CalendarView(props) {
  return <>{/* Read content and display on a calendar */}</>;

Builder.register('appTab', {
  name: 'Calendar',
  path: 'calendar',
  icon:  'https:/...',
  component: CalendarView,


Add a new tab located at the top of the preview window to view or edit the current document

E.g. create a notes tab that let's people post and view notes to collaborate

import { Builder } from '';
import { useObserver } from 'mobx-react'
const context = require('').default;

function NotesTab(props) {
  const { data } = context.designerState.editingContentModel;
  return useObserver(() =>
      onChange={e => data.set('notes',} /> 

Builder.register('editor.mainTab', {
  name: 'Notes',
  component: NotesTab,


Add a new tab located on the left sidebar to edit the currently selected element(s)

E.g. create a Tailwind UI tab that applies tailwind classes to elements

import { Builder } from '';
import { useObserver } from 'mobx-react'
const context = require('').default;

function TailwindTab(props) {
  const { selection } = context.designerState;
  return useObserver(() => 
    <input title="color" type="number" onChange={e => {
      selection.forEach(el => {
        let value =;'class', `text-gray-${value}`)
     } />

Builder.register('editor.editTab', {
  name: 'Tailwind',
  component: TailwindTab,


Override the insert menu displaying components you can drop in custom

import { Builder } from '';
const { designerState } = require('').default;

function InsertTab(props) {
  return <>
      onClick={() => 
        designerState.draggingInItem = 'Custom component 1' 
      } />
      onClick={() => 
        designerState.draggingInItem = 'Custom component 2' 
      } />

Builder.register('editor.insertTab', {
  component: InsertTab,


Add a toolbar button

E.g. create a workflow status button for custom workflows

import { Builder } from '';
const { designerState } = require('').default;

function WorkflowButton(props) {
  return <div onClick={launchApprovalModal}>
     Pending approval

Builder.register('editor.toolbarButton', {
  component: WorkflowButton,

Editor settings

You can also update various editor settings:

import { Builder } from ''

Builder.register('editor.settings', {
  hideStyleTab: false,      // Hide the style tab
  hideMainTabs: false,      // Hide all main tabs
  hideDataTab: false ,      // Hide the data tab
  hideOptionsTab: false,    // Hide the options tab
  hideToolbar: false,       // Hide the main toolbar
  hideHeatMap: false,       // Hide the heatmap button
  hidePageUrlEditor: false, // Hide the page URL editor
  hideAnimateTab: false,    // Hide the animate tab
  hideInsertTab: false,     // Hide the insert tab
  hideTargeting: false,     // Hide the targeting UI

App Context

You may notice the example above, and our open source examples, use this. It gives access to application state, including the current editing document, API access, etc.

See here for docs and type definitions for what is available in app state.

Was this article helpful?