--- 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)
\| string | | | 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
\| 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
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 ``` `admin/config.yml` (or `admin/config.js`) ```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: '__' } ] } ] ``` ## 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; }; ```