---
group: Customization
title: Creating Custom Widgets
weight: 40
---

The Static CMS exposes a `window.CMS` global object that you can use to register custom widgets via `registerWidget`. The same object is also the default export if you import Static CMS as an npm module.

### React Components Inline

The `registerPreviewTemplate` requires you to provide a React component. If you have a build process in place for your project, it is possible to integrate with this build process.

However, although possible, it may be cumbersome or even impractical to add a React build phase. For this reason, Static CMS exposes some constructs globally to allow you to create components inline: `h` (alias for React.createElement) as well some basic hooks (`useState`, `useMemo`, `useEffect`, `useCallback`).

**NOTE**: `createClass` is still provided, allowing for the creation of react class components. However it has now been deprecated and will be removed in `v2.0.0`.

## Register Widget

Register a custom widget.

```js
// Using global window object
CMS.registerWidget(name, control, [preview], [schema]);

// Using npm module import
import CMS from '@staticcms/core';
CMS.registerWidget(name, control, [preview], [schema]);
```

### Params

| Param   | Type                                                                                          | Description                                                                                                                                                                                                                                       |
| ------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name    | string                                                                                        | Widget name, allows this widget to be used via the field `widget` property in config                                                                                                                                                              |
| control | [React Function Component](https://reactjs.org/docs/components-and-props.html)<br />\| string | <ul><li>`React Function Component` - The react component that renders the control. See [Control Component](#control-component)</li><li>`string` - Name of a registered widget whose control should be used (includes built in widgets).</li></ul> |
| preview | [React Function Component](https://reactjs.org/docs/components-and-props.html)                | _Optional_. Renders the widget preview. See [Preview Component](#preview-component)                                                                                                                                                               |
| options | object                                                                                        | _Optional_. Widget options. See [Options](#options)                                                                                                                                                                                               |

### Control Component

The react component that renders the control. It receives the following props:

| Param               | Type                     | Description                                                                                               |
| ------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------- |
| label               | string                   | The label for the widget                                                                                  |
| value               | An valid widget value    | The current value of the widget                                                                           |
| onChange            | function                 | Function to be called when the value changes. Accepts a valid widget value                                |
| field               | object                   | The field configuration for the current widget. See [Widget Options](/docs/widgets#common-widget-options) |
| collection          | object                   | The collection configuration for the current widget. See [Collections](/docs/collection-overview)         |
| config              | object                   | The current Static CMS config. See [configuration options](/docs/configuration-options)                   |
| entry               | object                   | Object with a `data` field that contains the current value of all widgets in the editor                   |
| path                | string                   | `.` separated string donating the path to the current widget within the entry                             |
| hasErrors           | boolean                  | Specifies if there are validation errors with the current widget                                          |
| fieldsErrors        | object                   | Key/value object of field names mapping to validation errors                                              |
| isDisabled          | boolean                  | Specifies if the widget control should be disabled                                                        |
| submitted           | boolean                  | Specifies if a save attempt has been made in the editor session                                           |
| forList             | boolean                  | Specifices if the widget is within a `list` widget                                                        |
| isFieldDuplicate    | function                 | Function that given a field configuration, returns if that field is a duplicate                           |
| isFieldHidden       | function                 | Function that given a field configuration, returns if that field is hidden                                |
| getAsset            | Async function           | Function that given a url returns (as a promise) a loaded asset                                           |
| locale              | string<br />\| undefined | The current locale of the editor                                                                          |
| mediaPaths          | object                   | Key/value object of control IDs (passed to the media library) mapping to media paths                      |
| clearMediaControl   | function                 | Clears a control ID's value from the internal store                                                       |
| openMediaLibrary    | function                 | Opens the media library popup. See [Open Media Library](#open-media-library)                              |
| removeInsertedMedia | function                 | Removes draft media for a give control ID                                                                 |
| removeMediaControl  | function                 | Clears a control ID completely from the internal store                                                    |
| query               | function                 | Runs a search on another collection. See [Query](#query)                                                  |
| i18n                | object                   | The current i18n settings                                                                                 |
| t                   | function                 | Translates a given key to the current locale                                                              |

#### Open Media Library

`openMediaLibrary` allows you to open up the media library popup. It accepts the following props:

| Param         | Type                        | Default | Description                                                                                                              |
| ------------- | --------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ |
| controlID     | string                      |         | _Optional_ A unique identifier to which the uploaded media will be linked                                                |
| forImage      | boolean                     | `false` | _Optional_ If `true`, restricts upload to image files only                                                               |
| value         | string<br />list of strings |         | _Optional_ The current selected media value                                                                              |
| allowMultiple | boolean                     |         | _Optional_ Allow multiple files or images to be uploaded at once. Only used on media libraries that support multi upload |
| replaceIndex  | number                      |         | _Optional_ The index of the image in an list. Ignored if ` allowMultiple` is `false`                                     |
| config        | object                      |         | _Optional_ Media library config options. Available options depend on the media library being used                        |
| field         | object                      |         | _Optional_ The current field configuration                                                                               |

#### Query

`query` allows you to search the entries of a given collection. It accepts the following props:

| Param          | Type            | Default | Description                                                                            |
| -------------- | --------------- | ------- | -------------------------------------------------------------------------------------- |
| namespace      | string          |         | Unique identifier for search                                                           |
| collectionName | string          |         | The collection to be searched                                                          |
| searchFields   | list of strings |         | The Fields to be searched within the target collection                                 |
| searchTerm     | string          |         | The term to search with                                                                |
| file           | string          |         | _Optional_ The file in a file collection to search. Ignored on folder collections      |
| limit          | string          |         | _Optional_ The number of results to return. If not specified, all results are returned |

### Preview Component

The react component that renders the preview. It receives the following props:

| Param      | Type                  | Description                                                                                               |
| ---------- | --------------------- | --------------------------------------------------------------------------------------------------------- |
| value      | An valid widget value | The current value of the widget                                                                           |
| field      | object                | The field configuration for the current widget. See [Widget Options](/docs/widgets#common-widget-options) |
| collection | object                | The collection configuration for the current widget. See [Collections](/docs/collection-overview)         |
| config     | object                | The current Static CMS config. See [configuration options](/docs/configuration-options)                   |
| entry      | object                | Object with a `data` field that contains the current value of all widgets in the editor                   |
| getAsset   | Async function        | Function that given a url returns (as a promise) a loaded asset                                           |

### Options

Register widget takes an optional object of options. These options include:

| Param         | Type               | Description                                                                                                             |
| ------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| validator     | function           | _Optional_. Validates the value of the widget                                                                           |
| getValidValue | string             | _Optional_. Given the current value, returns a valid value. See [Advanced field validation](#advanced-field-validation) |
| schema        | JSON Schema object | _Optional_. Enforces a schema for the widget's field configuration                                                      |

### Example

`admin/index.html`

```html
<script src="https://unpkg.com/@staticcms/core@%5E1.0.0/dist/static-cms-core.js"></script>
<script>
  const CategoriesControl = ({ label, value, field, onChange }) => {
    const separator = useMemo(() => field.separator ?? ', ', [field.separator]);

    const handleChange = useCallback((e) => {
      onChange(e.target.value.split(separator).map(e => e.trim()));
    }, [separator, onChange]);

    return h('div', {}, {
      h('label', { for: 'inputId' }, label),
      h('input', {
        id: 'inputId',
        type: 'text',
        value: value ? value.join(separator) : '',
        onChange: this.handleChange,
      })
    });
  };

  const CategoriesPreview = ({ value }) => {
    return h(
      'ul',
      {},
      value.map(function (val, index) {
        return h('li', { key: index }, val);
      }),
    );
  };

  const schema = {
    properties: {
      separator: { type: 'string' },
    },
  };

  CMS.registerWidget('categories', CategoriesControl, CategoriesPreview, options: { schema });
</script>
```

`admin/config.yml` (or `admin/config.js`)

<CodeTabs>
```yaml
collections:
  - name: posts
    label: Posts
    folder: content/posts
    fields:
      - name: title
        label: Title
        widget: string
      - name: categories
        label: Categories
        widget: categories
        separator: __
```

```js
collections: [
  {
    name: 'posts',
    label: 'Posts',
    folder: 'content/posts',
    fields: [
      {
        name: 'title'
        label: 'Title'
        widget: 'string'
      },
      {
        name: 'categories'
        label: 'Categories'
        widget: 'categories'
        separator: '__'
      }
    ]
  }
]
```
</CodeTabs>

## Advanced field validation

All widget fields, including those for built-in widgets, [include basic validation](/docs/widgets/#common-widget-options) capability using the `required` and `pattern` options.

With custom widgets, the widget can also optionally pass in a `validator` method to perform custom validations, in addition to presence and pattern. The `validator` function will be automatically called, and it can return either a `boolean` value, an `object` with a type and error message or a promise.

### Examples

#### No Errors

```javascript
const validator = () => {
  // Do internal validation
  return true;
};
```

#### Has Error

```javascript
const validator = () => {
  // Do internal validation
  return false;
};
```

#### Error With Type

```javascript
const validator = () => {
  // Do internal validation
  return { type: 'custom-error' };
};
```

#### Error With Type and Message

_Useful for returning custom error messages_

```javascript
const validator = () => {
  // Do internal validation
  return { type: 'custom-error', message: 'Your error message.' };
};
```

#### Promise

You can also return a promise from `validator`. The promise can return `boolean` value, an `object` with a type and error message or a promise.

```javascript
const validator = () => {
  return this.existingPromise;
};
```
