---
title: Custom Widgets
position: 35
---
# Custom Widgets
The NetlifyCMS exposes an `window.CMS` global object that you can use to register custom widgets, previews, and editor plugins. The available widget extension methods are:
* **registerWidget:** lets you register a custom widget.
* **registerEditorComponent:** lets you add a block component to the Markdown editor.
### Writing React Components inline
The `registerWidget` 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, NetlifyCMS exposes two constructs globally to allow you to create components inline: ‘createClass’ and ‘h’ (alias for React.createElement).
## `registerWidget`
Register a custom widget.
```js
CMS.registerWidget(name, control, \[preview\])
```
**Params:**
Param | Type | Description
--- | --- | ---
`name` | string | Widget name, allows this widget to be used via the field `widget` property in config
`control` | React.Component \| string |
- React component that renders the control, receives the following props:
- **value:** Current field value
- **onChange:** Callback function to update the field value
- Name of a registered widget whose control should be used (includes built in widgets).
[`preview`] | React.Component, optional | Renders the widget preview, receives the following props: - **value:** Current preview value
- **field:** Immutable map of current field configuration
- **metadata:** Immutable map of any available metadata for the current field
- **getAsset:** Function for retrieving an asset url for image/file fields
- **entry:** Immutable Map of all entry data
- **fieldsMetaData:** Immutable map of metadata from all fields.
* **field:** The field type that this widget will be used for.
* **control:** A React component that renders the editing interface for this field. Two props will be passed:
* **value:** The current value for this field.
* **onChange:** Callback function to update the field value.
* **preview (optional):** A React component that renders the preview of how the content will look. A `value` prop will be passed to this component.
**Example:**
```html
```
## `registerEditorComponent`
Register a block level component for the Markdown editor:
CMS.registerEditorComponent(definition)
**Params**
* **definition:** The component definition; must specify: id, label, fields, patterns, fromBlock, toBlock, toPreview
**Example:**
```html
```
**Result:**
![youtube-widget](/img/youtube-widget.png)
## Advanced field validation
All widget fields, including those for built-in widgets, [include basic validation](https://www.netlifycms.org/docs/widgets/#common-widget-options) capability using the `required` and `pattern` options.
With custom widgets, the widget control can also optionally implement an `isValid` method to perform custom validations, in addition to presence and pattern. The `isValid` method will be automatically called, and it can return either a boolean value, an object with an error message or a promise. Examples:
**Boolean**
No errors:
```javascript
isValid = () => {
// Do internal validation
return true;
};
```
Existing error:
```javascript
isValid = () => {
// Do internal validation
return false;
};
```
**Object with `error` (useful for returning custom error messages)**
Existing error:
```javascript
isValid = () => {
// Do internal validation
return { error: 'Your error message.' };
};
```
**Promise**
You can also return a promise from `isValid`. While the promise is pending, the widget will be marked as "in error". When the promise resolves, the error is automatically cleared.
```javascript
isValid = () => {
return this.existingPromise;
};
```
Note: Do not create a promise inside `isValid` - `isValid` is called right before trying to persist. This means that even if a previous promise was already resolved, when the user hits 'save', `isValid` will be called again. If it returns a new promise, it will be immediately marked as "in error" until the new promise resolves.