---
title: Create Custom Adorners
product: Survey Creator
description: Custom adorner actions ensure even easier management of your survey elements right on the design surface. View a free demo example for JavaScript to learn more.
framework: React
source: https://surveyjs.io/survey-creator/examples/create-custom-adorners/reactjs
index: https://surveyjs.io/survey-creator/examples/overview.md
---

# Create Custom Adorners (React)

Adorners are interactive design-surface controls placed within a question area. Adorners allow users to quickly execute the most common actions: duplicate a question, mark a question as required, or delete it. This demo shows how to customize built-in adorners and create custom adorners.

## Create a Button Adorner

A button adorner executes a simple action on click. To create a button adorner, follow the steps below:

1. Handle the [`onElementGetActions`](https://surveyjs.io/survey-creator/documentation/api-reference/survey-creator#onElementGetActions) event.        
This event is raised when Survey Creator renders adorners on the design surface.

2. Create an `Action` instance.        
Pass an [`IAction`](https://surveyjs.io/form-library/documentation/api-reference/iaction) configuration object to the `Action` constructor. This object describes an action item rendered as a button adorner.

3. Add the `Action` instance to the `options.actions` array.       

This demo shows how to create a custom Read-Only button adorner. Refer to the code listing for more information. 

## Create a Drop-Down Adorner

A drop-down adorner opens a drop-down menu on click. The following instructions describe how to create a drop-down adorner:

1. Handle the [`onElementGetActions`](https://surveyjs.io/survey-creator/documentation/api-reference/survey-creator#onElementGetActions) event.

2. Create an `Action` instance.     
Drop-down adorners have a dedicated `createDropdownActionModel()` helper function that generates `Action` instances based on [`IAction`](https://surveyjs.io/form-library/documentation/api-reference/iaction) and `IActionDropdownPopupOptions` configuration objects. Import this function from `survey-core` and pass `IAction` and `IActionDropdownPopupOptions` objects to it.

3. Add the `Action` instance to the `options.actions` array.

In this demo, a custom Sort Order drop-down adorner lets users specify the order of items in choice-based questions. For details about implementation, view code listings for Angular, React, Vue, jQuery, or Vanilla JavaScript.

## 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/survey_json.js`

```js
export const surveyJSON = {
  "elements": [
    {
      "type": "text",
      "name": "Single-Line Input"
    },
    {
      "type": "checkbox",
      "name": "Checkboxes",
      "choices": [
        "Item 1",
        "Item 2",
        "Item 3"
      ]
    }
  ]
};
```

### `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 { Serializer, Action, ComputedUpdater, createDropdownActionModel, QuestionSelectBase } from "survey-core";
import { surveyJSON } from "./survey_json";
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();
    function createReadOnlyAction(question) {
        return new Action({
            id: "readOnly",
            active: new ComputedUpdater(() => question.readOnly),
            title: "Read-Only",
            iconName: "icon-editing-finish",        
            action: () => {
                question.readOnly = !question.readOnly;
            },
            // Place Read-Only before the Duplicate adorner whose `visibleIndex` is 10
            visibleIndex: 9
        });
    }
    function createSortOrderAction(selectBaseQuestion) {
        const sortOrderOptions = [
            { id: "none", title: "None" },
            { id: "asc", title: "Ascending" },
            { id: "desc", title: "Descending" },
            { id: "random", title: "Random" }
        ];
        function getTitle(selectBaseQuestion) {
            return sortOrderOptions.filter(
              (order) => order.id === selectBaseQuestion.choicesOrder
            )[0].title;
        }
        return createDropdownActionModel(
            {
                id: "sortOrder",   
                // Update a title caption to display the currently selected choice order
                title: new ComputedUpdater(() => {
                    return getTitle(selectBaseQuestion);
    
                }),
                // Place Sort Order before the custom Read-Only adorner
                visibleIndex: 8,
                // With the `sv-action--convertTo` class, a drop-down adorner
                // displays the selected value instead of the title
                css: "sv-action--convertTo sv-action-bar-item--secondary"            
            },
            {
                items: sortOrderOptions,
                allowSelection: true,
                onSelectionChanged: (item) => {
                    selectBaseQuestion.choicesOrder = item.id;
                },
                verticalPosition: "top",
                horizontalPosition: "center"
            }
        );
    }
    creator.onElementGetActions.add((_, options) => {
        const question = options.element;
        // Hide the titles of built-in adorners, except for "Element Type" and "Input Type"
        options.actions.forEach((action) => {
            if (["convertTo", "convertInputType"].indexOf(action.id) < 0) {
                action.showTitle = false;
            }
        });
        // Create a "Read-only" adorner for all question types
        const readOnlyAdorner = createReadOnlyAction(question);
        options.actions.push(readOnlyAdorner);
    
        // Create a "Sort Order" adorner for all choice-based questions
        if (question instanceof QuestionSelectBase) {
            const sortOrderAdorner = createSortOrderAction(question);
            options.actions.push(sortOrderAdorner);
        }
    });
    
    creator.JSON = surveyJSON;
    return (<SurveyCreatorComponent creator={creator} />);
}

export default SurveyCreatorRenderComponent;
```

### `src/index.css`

```css
/* You can add your custom CSS here. */
```

### `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/create-custom-adorners/angular.md)
- [Vue 3](https://surveyjs.io/survey-creator/examples/create-custom-adorners/vue3js.md)
- [jQuery](https://surveyjs.io/survey-creator/examples/create-custom-adorners/jquery.md)
- [Vanilla JS](https://surveyjs.io/survey-creator/examples/create-custom-adorners/vanillajs.md)
