---
title: Runtime Toolbox Customization
product: Survey Creator
description: Enable your end users to customize the toolbox by adding and removing its elements, e.g., question and panel types. View a free demo for JavaScript.
framework: React
source: https://surveyjs.io/survey-creator/examples/customize-toolbox-at-runtime/reactjs
index: https://surveyjs.io/survey-creator/examples/overview.md
---

# Runtime Toolbox Customization (React)

Survey Creator users can change the collection of available toolbox items and add new ones at runtime. In this demo, questions on the design surface have a **Save to Toolbox** button. Clicking it saves the current question configuration as a new toolbox item. To manage toolbox items, click the **Customize Toolbox** button in the toolbar. This button opens a pop-up window where you can show and hide any toolbox items and delete unnecessary custom items. Please note that runtime toolbox customization is not supported out of the box and requires implementation by your development team, as shown in this example.

## Save Custom Items to the Toolbox

Perform the following steps to let users save custom question configurations to the Toolbox:

1. Create a toolbox item configuration object.          
A toolbox item configuration object should implement the [`IQuestionToolboxItem`](/survey-creator/documentation/api-reference/iquestiontoolboxitem) interface.

1. Add the custom item to the Toolbox.          
Access the [`QuestionToolbox`](/survey-creator/documentation/api-reference/questiontoolbox) instance using Survey Creator's [`toolbox`](/survey-creator/documentation/api-reference/survey-creator#toolbox) property and call the [`addItem(item, index)`](/survey-creator/documentation/api-reference/questiontoolbox#addItem) method on this instance.

1. Add a UI element that saves custom toolbox items.
You can use any UI element that suits your use case. This demo uses the [`onElementGetActions`](/survey-creator/documentation/api-reference/survey-creator#onElementGetActions) event to add a custom button ([adorner](/survey-creator/documentation/end-user-guide/user-interface#adorners)) to each question on the design surface. A click on this button call a `saveCustomItem` function that creates a `IQuestionToolboxItem` object and adds it to the Toolbox.

Refer to the Code tab for a code example. Code lines that implement the steps above are marked with comments.

## Manage Toolbox Items

If you want to let users add and remove items from the Toolbox, follow the instructions below:

1. Create a survey that displays the dialog content.        
A pop-up dialog is built upon a regular survey from [SurveyJS Form Library](/form-library/documentation/overview). The survey displays a list of predefined toolbox items using a [Checkboxes](/form-library/examples/create-checkboxes-question-in-javascript/) question and allows users to delete unnecessary custom toolbox items using a [Dynamic Matrix](/form-library/examples/dynamic-matrix-add-new-rows/) question. Implement a function that returns the survey JSON schema (view the `createToolboxSetupSurveyJson()` function in code listings).

1. Populate the survey with lists of predefined and custom toolbox items.       
Access an array of toolbox [`items`](/survey-creator/documentation/api-reference/questiontoolbox#items), use it to prepare data arrays for the Checkboxes and Dynamic Matrix questions, and assign these arrays to the questions' [`value`](/form-library/documentation/api-reference/question#value) property (view the `populateToolboxSetupSurvey()` function).

1. Add a custom button that opens the dialog window.           
Configure the button by defining an [`IAction`](https://surveyjs.io/form-library/documentation/api-reference/iaction) object and passing it the `Action` constructor. This button can be added to the Survey Creator toolbar.

1. Apply the changes made in the dialog window.         
When users click Apply in the dialog window, you need to clear the Toolbox, collect selected toolbox items, and add them to the Toolbox anew (view the `showToolboxSetupPopup()` function).

## Files

### `public/index.html`

```html
<!-- Uncomment the following lines to enable Ace Editor in the JSON Editor tab -->
<!-- 
<script src="https://unpkg.com/ace-builds/src-min-noconflict/ace.js"></script>
<script src="https://unpkg.com/ace-builds/src-min-noconflict/ext-searchbox.js"></script>
<script src="https://unpkg.com/ace-builds/src-min-noconflict/theme-clouds_midnight.js"></script>
-->

<div id="surveyCreatorContainer" style="position: absolute; height: 100%; width: 100%"></div>
```

### `src/SurveyCreatorComponent.jsx`

```js
import React from "react";
import { SurveyCreator, SurveyCreatorComponent } from "survey-creator-react";
import "survey-core/survey.i18n";
import "survey-creator-core/survey-creator-core.i18n";
import { Model, settings, Action, JsonObject, ComputedUpdater } from "survey-core";
import "survey-core/survey-core.css";
import "survey-creator-core/survey-creator-core.css";
import "./index.css";

import SurveyTheme from "survey-core/themes";
import { registerCreatorTheme } from "survey-creator-core";

registerCreatorTheme(SurveyTheme); // Add predefined Survey Creator UI themes

function SurveyCreatorRenderComponent() {
    const creator = new SurveyCreator();
    const toolbox = creator.toolbox;
    toolbox.forceCompact = false;
    // #region Save Custom Items to the Toolbox 
    var customItems = {};
    const customCategoryName = "Custom Questions";
    
    function saveCustomItem (element) {
      const json = new JsonObject().toJsonObject(element);
      json.type = element.getType();
    
      if (!!customItems[element.name]) {
        creator.notify("A toolbox item with the same name already exists", "error");
        return;
      };
    
      // Step 1: Prepare a toolbox item configuration object
      const item = {
          name: element.name,
          iconName: "icon-" + element.getType(),
          title: element.title,
          json: json,
          category: customCategoryName
      };
      customItems[item.name] = item;
      // Step 2: Add the custom toolbox item to the top
      toolbox.addItem(item, 0);
    }
    
    // Step 3: Add a custom adorner that saves a question configuration as a toolbox item
    creator.onElementGetActions.add((_, options) => {
        if (options.element["isPage"]) return;
        const elemToAdd = options.element;
        options.actions.unshift({
            id: "save-to-toolbox",
            title: "Save to Toolbox",
            iconName: "icon-toolbox",        
            action: () => {
                saveCustomItem(elemToAdd);
            }
        });
    });
    // #endregion
    
    // #region Manage Toolbox Items
    const predefinedItems = {};
    
    const defaultToolboxItems = [].concat(toolbox.items);
    
    // Step 1: Create a survey that displays the dialog content
    function createToolboxSetupSurveyJson () {
        const choices = [];
        const value = [];
        defaultToolboxItems.forEach(({ name, title, iconName, json, tooltip, category }) => {
            choices.push({ value: name, text: title });
            value.push(name);
            predefinedItems[name] = {
                name: name,
                iconName: iconName,
                json: json,
                title: title,
                tooltip: tooltip,
                category: category
            };
        });
        return {
          "showNavigationButtons": false,
          "elements": [{
            "type": "checkbox",
            "name": "predefinedItems",
            "title": "Standard questions",
            "choices": choices,
            "defaultValue": value
          }, {
            "type": "matrixdynamic",
            "name": "customItems",
            "title": "Custom Questions",
            "showHeader": false,
            "columns": [{
              "name": "enabled",
              "cellType": "boolean",
              "defaultValue": true,
              "renderAs": "checkbox",
              "width": "15px",
              "minWidth": "15px",
            }, {
              "name": "question-name",
              "cellType": "dropdown",
              "readOnly": true
            }],
            "rowCount": 0,
            "allowAddRows": false,
            "hideColumnsIfEmpty": true,
            "noRowsText": "There are no custom questions."
          }]
        };
    }
    
    function isItemUsed (name) {
      return !!toolbox.getItemByName(name);
    }
    
    // Step 2: Populate the survey with lists of predefined and custom toolbox items
    function populateToolboxSetupSurvey (survey) {
        const selectedPredefinedItems = [];
        toolbox.items.forEach((item) => {
            selectedPredefinedItems.push(item.name);
        });
        const qPredefinedItems = survey.getQuestionByName("predefinedItems");
        qPredefinedItems.value = selectedPredefinedItems;
    
        const availableCustomItems = [];
        const selectedCustomItems = [];
        Object.keys(customItems).forEach((key) => {
            const item = customItems[key];
            availableCustomItems.push({ value: item.name, text: item.title });
            selectedCustomItems.push({
                enabled: isItemUsed(item.name),
                "question-name": item.name
            });
        });
        const qCustomItems = survey.getQuestionByName("customItems");
        qCustomItems.visible = availableCustomItems.length > 0;
        qCustomItems.choices = availableCustomItems;
        qCustomItems.value = selectedCustomItems;
        return [ qPredefinedItems, qCustomItems ];
    }
    
    // Step 3: Add a custom button that opens the dialog window with toolbox customization options
    const toolboxCustomizationAction = new Action({
        id: "toolbox-customization",
        iconName: "icon-toolbox",
        tooltip: "Customize Toolbox",
        visible: new ComputedUpdater(() => {
            return creator.activeTab === "designer";
        }),
        enabled: true,
        action: () => {
            showToolboxSetupPopup();
        }
    });
    // Add the custom button to the top toolbar
    creator.toolbarItems.push(toolboxCustomizationAction);
    // Add the custom button to the bottom toolbar (visible only on mobile devices)
    creator.footerToolbar.actions.push(toolboxCustomizationAction);
    
    function showToolboxSetupPopup () {
        const toolboxSetupSurvey = new Model(createToolboxSetupSurveyJson());
    
        const [ qPredefinedItems, qCustomItems ] = populateToolboxSetupSurvey(toolboxSetupSurvey);
    
        const popupOptions = {
            title: "Configure Toolbox Items",
            componentName: "survey",
            data: { model: toolboxSetupSurvey, survey: toolboxSetupSurvey },
            cssClass: "setup-toolbox-popup",
            // Step 4: Apply the changes made in the dialog window
            onApply: () => {
                const items = [];
    
                // Clear the Toolbox
                toolbox.clearItems();
    
                // Collect selected custom toolbox items
                if (Array.isArray(qCustomItems.value)) {
                    const updatedCustomQuestions = {};
                    qCustomItems.value.forEach((obj) => {
                        const qName = obj["question-name"];
                        const customItem = customItems[qName];
                        updatedCustomQuestions[qName] = customItem;
                        if (obj.enabled) {
                            items.push(customItem);
                        }
                    });
                    customItems = updatedCustomQuestions; 
                }
    
                // Collect selected predefined toolbox items
                for (let key in predefinedItems) {
                  if (Array.isArray(qPredefinedItems.value) && qPredefinedItems.value.indexOf(key) > -1) {
                      items.push(predefinedItems[key]);
                  }
                }
    
                // Add the selected items to the Toolbox
                items.forEach((item) => {
                    toolbox.addItem(item);
                });
                return true;
            }
        };
        settings.showDialog(popupOptions);
    }
    // #endregion
    
    creator.JSON = {
      "elements": [{
        "type": "text",
        "name": "question1",
        "title": "Question 1"
      }]
    }
    return (<SurveyCreatorComponent creator={creator} />);
}

export default SurveyCreatorRenderComponent;
```

### `src/index.css`

```css
.sv_main .sv_custom_header {
    display: none;
}

.setup-toolbox-popup .sd-root-modern {
    min-width: 640px;
}
```

### `src/index.js`

```js
import React from "react";
import { createRoot } from "react-dom/client";
import SurveyCreatorRenderComponent from "./SurveyCreatorComponent";

const root = createRoot(document.getElementById("surveyCreatorContainer"));
root.render(<SurveyCreatorRenderComponent />);
```

### `package.json`

```json
{
  "dependencies": {
    "react": "latest",
    "react-dom": "latest",
    "survey-core": "latest",
    "survey-react-ui": "latest",
    "survey-creator-core": "latest",
    "survey-creator-react": "latest"
  },
  "devDependencies": {
    "react-scripts": "latest"
  }
}
```

## Other Frameworks

- [Angular](https://surveyjs.io/survey-creator/examples/customize-toolbox-at-runtime/angular.md)
- [Vue 3](https://surveyjs.io/survey-creator/examples/customize-toolbox-at-runtime/vue3js.md)
- [jQuery](https://surveyjs.io/survey-creator/examples/customize-toolbox-at-runtime/jquery.md)
- [Vanilla JS](https://surveyjs.io/survey-creator/examples/customize-toolbox-at-runtime/vanillajs.md)
