Creating Custom Widgets
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.
// 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 | string |
|
| preview | React Function Component | Optional. Renders the widget preview. See Preview Component |
| options | object | Optional. Widget options. See 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 |
| collection | object | The collection configuration for the current widget. See Collections |
| config | object | The current Static CMS config. See 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 |
| 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 |
| 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 |
| collection | object | The collection configuration for the current widget. See Collections |
| config | object | The current Static CMS config. See 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 |
| schema | JSON Schema object | Optional. Enforces a schema for the widget's field configuration |
Example
admin/index.html
<script src="https://unpkg.com/@staticcms/app@%5E1.0.0/dist/static-cms-app.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)
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 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
const validator = () => {
// Do internal validation
return true;
};
Has Error
const validator = () => {
// Do internal validation
return false;
};
Error With Type
const validator = () => {
// Do internal validation
return { type: 'custom-error' };
};
Error With Type and Message
Useful for returning custom error messages
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.
const validator = () => {
return this.existingPromise;
};