{"id":111,"date":"2026-02-12T10:06:21","date_gmt":"2026-02-12T10:06:21","guid":{"rendered":"https:\/\/www.netlifycms.org\/?p=111"},"modified":"2026-04-12T10:08:20","modified_gmt":"2026-04-12T10:08:20","slug":"creating-custom-widgets","status":"publish","type":"post","link":"https:\/\/www.netlifycms.org\/docs\/custom-widgets\/","title":{"rendered":"Creating Custom Widgets"},"content":{"rendered":"<p>The <strong>NetlifyCMS<\/strong> exposes a <code>window.CMS<\/code> a global object that you can use to register custom widgets, previews, and editor plugins. The same object is also the default export if you import <strong>Netlify CMS<\/strong> as an npm module. The available widget extension methods are:<\/p>\n<ul>\n<li><strong>registerWidget:<\/strong> registers a custom widget.<\/li>\n<li><strong>registerEditorComponent:<\/strong> adds a block component to the Markdown editor.<\/li>\n<\/ul>\n<h3 id=\"writing-react-components-inline\">Writing React Components inline<\/h3>\n<p>The <code>registerWidget<\/code> 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.<\/p>\n<p>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: \u2018createClass\u2019 and \u2018h\u2019 (alias for React.createElement).<\/p>\n<h2 id=\"registerwidget\"><code>registerWidget<\/code><\/h2>\n<p>Register a custom widget.<\/p>\n<div class=\"gatsby-highlight\" data-language=\"js\">\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">\/\/ Using global window object<\/span>\r\n<span class=\"token constant\">CMS<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">registerWidget<\/span><span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">,<\/span> control<span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">[<\/span>preview<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">[<\/span>schema<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n<span class=\"token comment\">\/\/ Using npm module import<\/span>\r\n<span class=\"token keyword\">import<\/span> <span class=\"token constant\">CMS<\/span> <span class=\"token keyword\">from<\/span> <span class=\"token string\">'netlify-cms'<\/span><span class=\"token punctuation\">;<\/span>\r\n<span class=\"token constant\">CMS<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">registerWidget<\/span><span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">,<\/span> control<span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">[<\/span>preview<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">[<\/span>schema<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span><\/code><\/pre>\n<\/div>\n<p><strong>Params:<\/strong><\/p>\n<table>\n<thead>\n<tr>\n<th>Param<\/th>\n<th>Type<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>name<\/code><\/td>\n<td><code>string<\/code><\/td>\n<td>Widget name, allows this widget to be used via the field <code>widget<\/code> property in config<\/td>\n<\/tr>\n<tr>\n<td><code>control<\/code><\/td>\n<td><code>React.Component<\/code> or <code>string<\/code><\/td>\n<td>\n<ul>\n<li>React component that renders the control, receives the following props:\n<ul>\n<li><strong>value:<\/strong> Current field value<\/li>\n<li><strong>field:<\/strong> Immutable map of current field configuration<\/li>\n<li><strong>forID:<\/strong> Unique identifier for the field<\/li>\n<li><strong>classNameWrapper:<\/strong> class name to apply CMS styling to the field<\/li>\n<li><strong>onChange:<\/strong> Callback function to update the field value<\/li>\n<\/ul>\n<\/li>\n<li>Name of a registered widget whose control should be used (includes built in widgets).<\/li>\n<\/ul>\n<\/td>\n<\/tr>\n<tr>\n<td>[<code>preview<\/code>]<\/td>\n<td><code>React.Component<\/code>, optional<\/td>\n<td>Renders the widget preview, receives the following props:<\/p>\n<ul>\n<li><strong>value:<\/strong> Current preview value<\/li>\n<li><strong>field:<\/strong> Immutable map of current field configuration<\/li>\n<li><strong>metadata:<\/strong> Immutable map of any available metadata for the current field<\/li>\n<li><strong>getAsset:<\/strong> Function for retrieving an asset url for image\/file fields<\/li>\n<li><strong>entry:<\/strong> Immutable Map of all entry data<\/li>\n<li><strong>fieldsMetaData:<\/strong> Immutable map of metadata from all fields.<\/li>\n<\/ul>\n<\/td>\n<\/tr>\n<tr>\n<td>[<code>schema<\/code>]<\/td>\n<td><code>JSON Schema object<\/code>, optional<\/td>\n<td>Enforces a schema for the widget&#8217;s field configuration<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><strong>Example:<\/strong><\/p>\n<p><code>admin\/index.html<\/code><\/p>\n<div class=\"gatsby-highlight\" data-language=\"html\">\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>script <span class=\"token attr-name\">src<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=<\/span><span class=\"token punctuation\">\"<\/span>https:\/\/unpkg.com\/netlify-cms@^2.0.0\/dist\/netlify-cms.js<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>script<span class=\"token punctuation\">&gt;<\/span><\/span>\r\n<span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>script<span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token script\"><span class=\"token language-javascript\">\r\n<span class=\"token keyword\">var<\/span> CategoriesControl <span class=\"token operator\">=<\/span> <span class=\"token function\">createClass<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token function-variable function\">handleChange<\/span><span class=\"token operator\">:<\/span> <span class=\"token keyword\">function<\/span><span class=\"token punctuation\">(<\/span><span class=\"token parameter\">e<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token keyword\">const<\/span> separator <span class=\"token operator\">=<\/span> <span class=\"token keyword\">this<\/span><span class=\"token punctuation\">.<\/span>props<span class=\"token punctuation\">.<\/span>field<span class=\"token punctuation\">.<\/span><span class=\"token function\">get<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'separator'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">', '<\/span><span class=\"token punctuation\">)<\/span>\r\n    <span class=\"token keyword\">this<\/span><span class=\"token punctuation\">.<\/span>props<span class=\"token punctuation\">.<\/span><span class=\"token function\">onChange<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>target<span class=\"token punctuation\">.<\/span>value<span class=\"token punctuation\">.<\/span><span class=\"token function\">split<\/span><span class=\"token punctuation\">(<\/span>separator<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">map<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">(<\/span><span class=\"token parameter\">e<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">=&gt;<\/span> e<span class=\"token punctuation\">.<\/span><span class=\"token function\">trim<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n\r\n  <span class=\"token function-variable function\">render<\/span><span class=\"token operator\">:<\/span> <span class=\"token keyword\">function<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token keyword\">const<\/span> separator <span class=\"token operator\">=<\/span> <span class=\"token keyword\">this<\/span><span class=\"token punctuation\">.<\/span>props<span class=\"token punctuation\">.<\/span>field<span class=\"token punctuation\">.<\/span><span class=\"token function\">get<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'separator'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">', '<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n    <span class=\"token keyword\">var<\/span> value <span class=\"token operator\">=<\/span> <span class=\"token keyword\">this<\/span><span class=\"token punctuation\">.<\/span>props<span class=\"token punctuation\">.<\/span>value<span class=\"token punctuation\">;<\/span>\r\n    <span class=\"token keyword\">return<\/span> <span class=\"token function\">h<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'input'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span>\r\n      <span class=\"token literal-property property\">id<\/span><span class=\"token operator\">:<\/span> <span class=\"token keyword\">this<\/span><span class=\"token punctuation\">.<\/span>props<span class=\"token punctuation\">.<\/span>forID<span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token literal-property property\">className<\/span><span class=\"token operator\">:<\/span> <span class=\"token keyword\">this<\/span><span class=\"token punctuation\">.<\/span>props<span class=\"token punctuation\">.<\/span>classNameWrapper<span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token literal-property property\">type<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'text'<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token literal-property property\">value<\/span><span class=\"token operator\">:<\/span> value <span class=\"token operator\">?<\/span> value<span class=\"token punctuation\">.<\/span><span class=\"token function\">join<\/span><span class=\"token punctuation\">(<\/span>separator<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">:<\/span> <span class=\"token string\">''<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token literal-property property\">onChange<\/span><span class=\"token operator\">:<\/span> <span class=\"token keyword\">this<\/span><span class=\"token punctuation\">.<\/span>handleChange<span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n<span class=\"token keyword\">var<\/span> CategoriesPreview <span class=\"token operator\">=<\/span> <span class=\"token function\">createClass<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token function-variable function\">render<\/span><span class=\"token operator\">:<\/span> <span class=\"token keyword\">function<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token keyword\">return<\/span> <span class=\"token function\">h<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'ul'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token keyword\">this<\/span><span class=\"token punctuation\">.<\/span>props<span class=\"token punctuation\">.<\/span>value<span class=\"token punctuation\">.<\/span><span class=\"token function\">map<\/span><span class=\"token punctuation\">(<\/span><span class=\"token keyword\">function<\/span><span class=\"token punctuation\">(<\/span><span class=\"token parameter\">val<span class=\"token punctuation\">,<\/span> index<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span>\r\n        <span class=\"token keyword\">return<\/span> <span class=\"token function\">h<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'li'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token literal-property property\">key<\/span><span class=\"token operator\">:<\/span> index<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span> val<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n      <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span>\r\n    <span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n  <span class=\"token punctuation\">}<\/span>\r\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n<span class=\"token keyword\">var<\/span> schema <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token literal-property property\">properties<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token literal-property property\">separator<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token literal-property property\">type<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'string'<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n<span class=\"token punctuation\">}<\/span>\r\n\r\n<span class=\"token constant\">CMS<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">registerWidget<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'categories'<\/span><span class=\"token punctuation\">,<\/span> CategoriesControl<span class=\"token punctuation\">,<\/span> CategoriesPreview<span class=\"token punctuation\">,<\/span> schema<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n<\/span><\/span><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>script<span class=\"token punctuation\">&gt;<\/span><\/span><\/code><\/pre>\n<\/div>\n<p><code>admin\/config.yml<\/code><\/p>\n<div class=\"gatsby-highlight\" data-language=\"yml\">\n<pre class=\"language-yml\"><code class=\"language-yml\"><span class=\"token key atrule\">collections<\/span><span class=\"token punctuation\">:<\/span>\r\n  <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">name<\/span><span class=\"token punctuation\">:<\/span> posts\r\n    <span class=\"token key atrule\">label<\/span><span class=\"token punctuation\">:<\/span> Posts\r\n    <span class=\"token key atrule\">folder<\/span><span class=\"token punctuation\">:<\/span> content\/posts\r\n    <span class=\"token key atrule\">fields<\/span><span class=\"token punctuation\">:<\/span>\r\n      <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">name<\/span><span class=\"token punctuation\">:<\/span> title\r\n        <span class=\"token key atrule\">label<\/span><span class=\"token punctuation\">:<\/span> Title\r\n        <span class=\"token key atrule\">widget<\/span><span class=\"token punctuation\">:<\/span> string\r\n      <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">name<\/span><span class=\"token punctuation\">:<\/span> categories\r\n        <span class=\"token key atrule\">label<\/span><span class=\"token punctuation\">:<\/span> Categories\r\n        <span class=\"token key atrule\">widget<\/span><span class=\"token punctuation\">:<\/span> categories\r\n        <span class=\"token key atrule\">separator<\/span><span class=\"token punctuation\">:<\/span> __<\/code><\/pre>\n<\/div>\n<h2 id=\"registereditorcomponent\"><code>registerEditorComponent<\/code><\/h2>\n<p>Register a block level component for the Markdown editor:<\/p>\n<div class=\"gatsby-highlight\" data-language=\"js\">\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token constant\">CMS<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">registerEditorComponent<\/span><span class=\"token punctuation\">(<\/span>definition<span class=\"token punctuation\">)<\/span><\/code><\/pre>\n<\/div>\n<p><strong>Params<\/strong><\/p>\n<ul>\n<li><strong>definition:<\/strong> The component definition; must specify: id, label, fields, patterns, fromBlock, toBlock, toPreview<\/li>\n<\/ul>\n<blockquote><p>Additional properties are optional and will be passed to the underlying widget control (object widget by default). For example, adding a <code>collapsed: true<\/code> property will collapse the widget by default.<\/p><\/blockquote>\n<p><strong>Example:<\/strong><\/p>\n<div class=\"gatsby-highlight\" data-language=\"html\">\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>script <span class=\"token attr-name\">src<\/span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=<\/span><span class=\"token punctuation\">\"<\/span>https:\/\/unpkg.com\/netlify-cms@^2.0.0\/dist\/netlify-cms.js<span class=\"token punctuation\">\"<\/span><\/span><span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>script<span class=\"token punctuation\">&gt;<\/span><\/span>\r\n<span class=\"token tag\"><span class=\"token punctuation\">&lt;<\/span>script<span class=\"token punctuation\">&gt;<\/span><\/span><span class=\"token script\"><span class=\"token language-javascript\">\r\n<span class=\"token constant\">CMS<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">registerEditorComponent<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token comment\">\/\/ Internal id of the component<\/span>\r\n  <span class=\"token literal-property property\">id<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"collapsible-note\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token comment\">\/\/ Visible label<\/span>\r\n  <span class=\"token literal-property property\">label<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"Collapsible Note\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token comment\">\/\/ Fields the user need to fill out when adding an instance of the component<\/span>\r\n  <span class=\"token literal-property property\">fields<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">[<\/span>\r\n    <span class=\"token punctuation\">{<\/span>\r\n      <span class=\"token literal-property property\">name<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'summary'<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token literal-property property\">label<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'Summary'<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token literal-property property\">widget<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'string'<\/span>\r\n    <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token punctuation\">{<\/span>\r\n      <span class=\"token literal-property property\">name<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'details'<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token literal-property property\">label<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'Details'<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token literal-property property\">widget<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'markdown'<\/span>\r\n    <span class=\"token punctuation\">}<\/span>\r\n  <span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token comment\">\/\/ Regex pattern used to search for instances of this block in the markdown document.<\/span>\r\n  <span class=\"token comment\">\/\/ Patterns are run in a multline environment (against the entire markdown document),<\/span>\r\n  <span class=\"token comment\">\/\/ and so generally should make use of the multiline flag (`m`). If you need to capture<\/span>\r\n  <span class=\"token comment\">\/\/ newlines in your capturing groups, you can either use something like<\/span>\r\n  <span class=\"token comment\">\/\/ `([\\S\\s]*)`, or you can additionally enable the \"dot all\" flag (`s`),<\/span>\r\n  <span class=\"token comment\">\/\/ which will cause `(.*)` to match newlines as well.<\/span>\r\n  <span class=\"token comment\">\/\/<\/span>\r\n  <span class=\"token comment\">\/\/ Additionally, it's recommended that you use non-greedy capturing groups (e.g.<\/span>\r\n  <span class=\"token comment\">\/\/ `(.*?)` vs `(.*)`), especially if matching against newline characters.<\/span>\r\n  <span class=\"token literal-property property\">pattern<\/span><span class=\"token operator\">:<\/span> <span class=\"token regex\"><span class=\"token regex-delimiter\">\/<\/span><span class=\"token regex-source language-regex\">^&lt;details&gt;$\\s*?&lt;summary&gt;(.*?)&lt;\\\/summary&gt;\\n\\n(.*?)\\n^&lt;\\\/details&gt;$<\/span><span class=\"token regex-delimiter\">\/<\/span><span class=\"token regex-flags\">ms<\/span><\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token comment\">\/\/ Given a RegExp Match object<\/span>\r\n  <span class=\"token comment\">\/\/ (https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/String\/match#return_value),<\/span>\r\n  <span class=\"token comment\">\/\/ return an object with one property for each field defined in `fields`.<\/span>\r\n  <span class=\"token comment\">\/\/<\/span>\r\n  <span class=\"token comment\">\/\/ This is used to populate the custom widget in the markdown editor in the CMS.<\/span>\r\n  <span class=\"token function-variable function\">fromBlock<\/span><span class=\"token operator\">:<\/span> <span class=\"token keyword\">function<\/span><span class=\"token punctuation\">(<\/span><span class=\"token parameter\">match<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token keyword\">return<\/span> <span class=\"token punctuation\">{<\/span>\r\n      <span class=\"token literal-property property\">summary<\/span><span class=\"token operator\">:<\/span> match<span class=\"token punctuation\">[<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token literal-property property\">detail<\/span><span class=\"token operator\">:<\/span> match<span class=\"token punctuation\">[<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">]<\/span>\r\n    <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token comment\">\/\/ Given an object with one property for each field defined in `fields`,<\/span>\r\n  <span class=\"token comment\">\/\/ return the string you wish to be inserted into your markdown.<\/span>\r\n  <span class=\"token comment\">\/\/<\/span>\r\n  <span class=\"token comment\">\/\/ This is used to serialize the data from the custom widget to the<\/span>\r\n  <span class=\"token comment\">\/\/ markdown document<\/span>\r\n  <span class=\"token function-variable function\">toBlock<\/span><span class=\"token operator\">:<\/span> <span class=\"token keyword\">function<\/span><span class=\"token punctuation\">(<\/span><span class=\"token parameter\">data<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token keyword\">return<\/span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`<\/span><span class=\"token string\">\r\n&lt;details&gt;\r\n  &lt;summary&gt;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>data<span class=\"token punctuation\">.<\/span>summary<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/summary&gt;\r\n\r\n  <\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>data<span class=\"token punctuation\">.<\/span>detail<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">\r\n\r\n&lt;\/details&gt;\r\n<\/span><span class=\"token template-punctuation string\">`<\/span><\/span><span class=\"token punctuation\">;<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token comment\">\/\/ Preview output for this component. Can either be a string or a React component<\/span>\r\n  <span class=\"token comment\">\/\/ (component gives better render performance)<\/span>\r\n  <span class=\"token function-variable function\">toPreview<\/span><span class=\"token operator\">:<\/span> <span class=\"token keyword\">function<\/span><span class=\"token punctuation\">(<\/span><span class=\"token parameter\">data<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token keyword\">return<\/span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`<\/span><span class=\"token string\">\r\n&lt;details&gt;\r\n  &lt;summary&gt;<\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>data<span class=\"token punctuation\">.<\/span>summary<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/summary&gt;\r\n\r\n  <\/span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${<\/span>data<span class=\"token punctuation\">.<\/span>detail<span class=\"token interpolation-punctuation punctuation\">}<\/span><\/span><span class=\"token string\">\r\n\r\n&lt;\/details&gt;\r\n<\/span><span class=\"token template-punctuation string\">`<\/span><\/span><span class=\"token punctuation\">;<\/span>\r\n  <span class=\"token punctuation\">}<\/span>\r\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n<\/span><\/span><span class=\"token tag\"><span class=\"token punctuation\">&lt;\/<\/span>script<span class=\"token punctuation\">&gt;<\/span><\/span><\/code><\/pre>\n<\/div>\n<p><strong>Result:<\/strong><\/p>\n<p>![youtube-widget](\/img\/screen shot 2018-01-05 at 4.25.07 pm.png)<\/p>\n<h2 id=\"advanced-field-validation\">Advanced field validation<\/h2>\n<p>All widget fields, including those for built-in widgets, <a href=\"https:\/\/web.archive.org\/web\/20220128220950\/https:\/\/www.netlifycms.org\/docs\/widgets\/#common-widget-options\">include basic validation<\/a> capability using the <code>required<\/code> and <code>pattern<\/code> options.<\/p>\n<p>With custom widgets, the widget control can also optionally implement an <code>isValid<\/code> method to perform custom validations, in addition to presence and pattern. The <code>isValid<\/code> method will be automatically called, and it can return either a boolean value, an object with an error message or a promise. Examples:<\/p>\n<p><strong>Boolean<\/strong> No errors:<\/p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token function-variable function\">isValid<\/span> <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">=&gt;<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token comment\">\/\/ Do internal validation<\/span>\r\n    <span class=\"token keyword\">return<\/span> <span class=\"token boolean\">true<\/span><span class=\"token punctuation\">;<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><\/code><\/pre>\n<\/div>\n<p>Existing error:<\/p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token function-variable function\">isValid<\/span> <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">=&gt;<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token comment\">\/\/ Do internal validation<\/span>\r\n    <span class=\"token keyword\">return<\/span> <span class=\"token boolean\">false<\/span><span class=\"token punctuation\">;<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><\/code><\/pre>\n<\/div>\n<p><strong>Object with <code>error<\/code> (useful for returning custom error messages)<\/strong> Existing error:<\/p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token function-variable function\">isValid<\/span> <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">=&gt;<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token comment\">\/\/ Do internal validation<\/span>\r\n    <span class=\"token keyword\">return<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token literal-property property\">error<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token literal-property property\">message<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'Your error message.'<\/span> <span class=\"token punctuation\">}<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><\/code><\/pre>\n<\/div>\n<p><strong>Promise<\/strong> You can also return a promise from <code>isValid<\/code>. While the promise is pending, the widget will be marked as &#8220;in error&#8221;. When the promise resolves, the error is automatically cleared.<\/p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">  <span class=\"token function-variable function\">isValid<\/span> <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">=&gt;<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token keyword\">return<\/span> <span class=\"token keyword\">this<\/span><span class=\"token punctuation\">.<\/span>existingPromise<span class=\"token punctuation\">;<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><\/code><\/pre>\n<\/div>\n<p><strong>Note:<\/strong> Do not create a promise inside <code>isValid<\/code> &#8211; <code>isValid<\/code> is called right before trying to persist. This means that even if a previous promise was already resolved, when the user hits &#8216;save&#8217;, <code>isValid<\/code> will be called again. If it returns a new promise, it will be immediately marked as &#8220;in error&#8221; until the new promise resolves.<\/p>\n<h2 id=\"writing-custom-widgets-as-a-separate-package\">Writing custom widgets as a separate package<\/h2>\n<p>Widgets are inputs for the Netlify CMS editor interface. It&#8217;s a React component that receives user input and outputs a serialized value. Those are the only rules &#8211; the component can be extremely simple, like text input, or extremely complicated, like a full-blown markdown editor. They can make calls to external services, and generally do anything that JavaScript can do.<\/p>\n<p>For writing custom widgets as a separate package you should follow these steps:<\/p>\n<ol>\n<li>Create a directory\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">mkdir my<span class=\"token operator\">-<\/span>custom<span class=\"token operator\">-<\/span>widget<\/code><\/pre>\n<\/div>\n<\/li>\n<li>Navigate to the directory\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">cd my<span class=\"token operator\">-<\/span>custom<span class=\"token operator\">-<\/span>widget<\/code><\/pre>\n<\/div>\n<\/li>\n<li>For setting up a new npm package run this command:\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">npm init<\/code><\/pre>\n<\/div>\n<\/li>\n<li>Answer the questions in the command line questionnaire.<\/li>\n<li>In order to build React components, we need to set up a build step. We&#8217;ll be using Webpack. Please run the following commands to install the required dependencies:<\/li>\n<\/ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">   npm install <span class=\"token operator\">--<\/span>save<span class=\"token operator\">-<\/span>dev babel<span class=\"token operator\">-<\/span>loader@<span class=\"token number\">7<\/span> babel<span class=\"token operator\">-<\/span>core babel<span class=\"token operator\">-<\/span>plugin<span class=\"token operator\">-<\/span>transform<span class=\"token operator\">-<\/span><span class=\"token keyword\">class<\/span><span class=\"token operator\">-<\/span>properties babel<span class=\"token operator\">-<\/span>plugin<span class=\"token operator\">-<\/span>transform<span class=\"token operator\">-<\/span><span class=\"token keyword\">export<\/span><span class=\"token operator\">-<\/span>extensions babel<span class=\"token operator\">-<\/span>plugin<span class=\"token operator\">-<\/span>transform<span class=\"token operator\">-<\/span>object<span class=\"token operator\">-<\/span>rest<span class=\"token operator\">-<\/span>spread babel<span class=\"token operator\">-<\/span>preset<span class=\"token operator\">-<\/span>env babel<span class=\"token operator\">-<\/span>preset<span class=\"token operator\">-<\/span>react cross<span class=\"token operator\">-<\/span>env css<span class=\"token operator\">-<\/span>loader html<span class=\"token operator\">-<\/span>webpack<span class=\"token operator\">-<\/span>plugin netlify<span class=\"token operator\">-<\/span>cms react source<span class=\"token operator\">-<\/span>map<span class=\"token operator\">-<\/span>loader style<span class=\"token operator\">-<\/span>loader webpack webpack<span class=\"token operator\">-<\/span>cli webpack<span class=\"token operator\">-<\/span>serve<\/code><\/pre>\n<\/div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">   npm install <span class=\"token operator\">--<\/span>save prop<span class=\"token operator\">-<\/span>types<\/code><\/pre>\n<\/div>\n<p>And you should manually add &#8220;<strong>peerDependencies<\/strong>&#8221; and &#8220;<strong>scripts<\/strong>&#8221; as shown below.<\/p>\n<p>Here is the content of <code>package.json<\/code> that you will have at the end:<\/p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token string-property property\">\"name\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"netlify-cms-widget-starter\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token string-property property\">\"description\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"A boilerplate for creating Netlify CMS widgets.\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token string-property property\">\"author\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"name of developer\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token string-property property\">\"keywords\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">[<\/span>\r\n    <span class=\"token string\">\"netlify\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"netlify-cms\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"cms\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"widget\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"starter\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"boilerplate\"<\/span>\r\n  <span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token string-property property\">\"version\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"0.0.1\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token string-property property\">\"homepage\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"https:\/\/github.com\/netlify\/netlify-cms-widget-starter\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token string-property property\">\"license\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"MIT\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token string-property property\">\"main\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"dist\/main.js\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token string-property property\">\"devDependencies\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token string-property property\">\"babel-loader\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^7.1.4\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"babel-plugin-transform-class-properties\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^6.24.1\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"babel-plugin-transform-export-extensions\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^6.22.0\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"babel-plugin-transform-object-rest-spread\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^6.26.0\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"babel-preset-env\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^1.6.1\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"babel-preset-react\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^6.24.1\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"cross-env\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^5.1.4\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"css-loader\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^0.28.11\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"html-webpack-plugin\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^3.2.0\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"netlify-cms\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^1.5.0\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"react\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^16.3.2\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"source-map-loader\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^0.2.3\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"style-loader\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^0.20.3\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"webpack\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^4.6.0\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"webpack-cli\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^2.0.14\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string-property property\">\"webpack-serve\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^0.3.1\"<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token string-property property\">\"dependencies\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token string-property property\">\"prop-types\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^15.6.1\"<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token string-property property\">\"peerDependencies\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token string-property property\">\"react\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"^16\"<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token string-property property\">\"scripts\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token string-property property\">\"start\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"webpack-serve --static public --open\"<\/span>\r\n  <span class=\"token punctuation\">}<\/span>\r\n<span class=\"token punctuation\">}<\/span><\/code><\/pre>\n<\/div>\n<ol start=\"5\">\n<li>Create a Webpack configuration file with this content:<code>webpack.config.js<\/code>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const<\/span> path <span class=\"token operator\">=<\/span> <span class=\"token function\">require<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'path'<\/span><span class=\"token punctuation\">)<\/span>\r\n<span class=\"token keyword\">const<\/span> HtmlWebpackPlugin <span class=\"token operator\">=<\/span> <span class=\"token function\">require<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'html-webpack-plugin'<\/span><span class=\"token punctuation\">)<\/span>\r\n\r\n<span class=\"token keyword\">const<\/span> developmentConfig <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token literal-property property\">mode<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'development'<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token literal-property property\">entry<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'.\/dev\/index.js'<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token literal-property property\">output<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token literal-property property\">path<\/span><span class=\"token operator\">:<\/span> path<span class=\"token punctuation\">.<\/span><span class=\"token function\">resolve<\/span><span class=\"token punctuation\">(<\/span>__dirname<span class=\"token punctuation\">,<\/span> <span class=\"token string\">'public'<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token literal-property property\">optimization<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token literal-property property\">minimize<\/span><span class=\"token operator\">:<\/span> <span class=\"token boolean\">false<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token literal-property property\">module<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token literal-property property\">rules<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">[<\/span>\r\n      <span class=\"token punctuation\">{<\/span>\r\n        <span class=\"token literal-property property\">test<\/span><span class=\"token operator\">:<\/span> <span class=\"token regex\"><span class=\"token regex-delimiter\">\/<\/span><span class=\"token regex-source language-regex\">\\.js$<\/span><span class=\"token regex-delimiter\">\/<\/span><\/span><span class=\"token punctuation\">,<\/span>\r\n        <span class=\"token literal-property property\">loader<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'source-map-loader'<\/span><span class=\"token punctuation\">,<\/span>\r\n        <span class=\"token literal-property property\">enforce<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'pre'<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token punctuation\">{<\/span>\r\n        <span class=\"token literal-property property\">test<\/span><span class=\"token operator\">:<\/span> <span class=\"token regex\"><span class=\"token regex-delimiter\">\/<\/span><span class=\"token regex-source language-regex\">\\.jsx?$<\/span><span class=\"token regex-delimiter\">\/<\/span><\/span><span class=\"token punctuation\">,<\/span>\r\n        <span class=\"token literal-property property\">exclude<\/span><span class=\"token operator\">:<\/span> <span class=\"token regex\"><span class=\"token regex-delimiter\">\/<\/span><span class=\"token regex-source language-regex\">node_modules<\/span><span class=\"token regex-delimiter\">\/<\/span><\/span><span class=\"token punctuation\">,<\/span>\r\n        <span class=\"token literal-property property\">loader<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'babel-loader'<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token punctuation\">{<\/span>\r\n        <span class=\"token literal-property property\">test<\/span><span class=\"token operator\">:<\/span> <span class=\"token regex\"><span class=\"token regex-delimiter\">\/<\/span><span class=\"token regex-source language-regex\">\\.css$<\/span><span class=\"token regex-delimiter\">\/<\/span><\/span><span class=\"token punctuation\">,<\/span>\r\n        <span class=\"token literal-property property\">use<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">{<\/span> <span class=\"token literal-property property\">loader<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'style-loader'<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token literal-property property\">loader<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'css-loader'<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token literal-property property\">plugins<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">[<\/span>\r\n    <span class=\"token keyword\">new<\/span> <span class=\"token class-name\">HtmlWebpackPlugin<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token literal-property property\">devtool<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'eval-source-map'<\/span><span class=\"token punctuation\">,<\/span>\r\n<span class=\"token punctuation\">}<\/span>\r\n\r\n<span class=\"token keyword\">const<\/span> productionConfig <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token literal-property property\">mode<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'production'<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token literal-property property\">module<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\r\n    <span class=\"token literal-property property\">rules<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">[<\/span>\r\n      <span class=\"token punctuation\">{<\/span>\r\n        <span class=\"token literal-property property\">test<\/span><span class=\"token operator\">:<\/span> <span class=\"token regex\"><span class=\"token regex-delimiter\">\/<\/span><span class=\"token regex-source language-regex\">\\.jsx?$<\/span><span class=\"token regex-delimiter\">\/<\/span><\/span><span class=\"token punctuation\">,<\/span>\r\n        <span class=\"token literal-property property\">loader<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'babel-loader'<\/span><span class=\"token punctuation\">,<\/span>\r\n      <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token literal-property property\">devtool<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'source-map'<\/span><span class=\"token punctuation\">,<\/span>\r\n<span class=\"token punctuation\">}<\/span>\r\n\r\nmodule<span class=\"token punctuation\">.<\/span>exports <span class=\"token operator\">=<\/span> process<span class=\"token punctuation\">.<\/span>env<span class=\"token punctuation\">.<\/span><span class=\"token constant\">NODE_ENV<\/span> <span class=\"token operator\">===<\/span> <span class=\"token string\">'production'<\/span> <span class=\"token operator\">?<\/span> productionConfig <span class=\"token operator\">:<\/span> developmentConfig<\/code><\/pre>\n<\/div>\n<\/li>\n<li>The <code>.babelrc<\/code> file is our local configuration for our code in the project. You should create it under the root of the application repo. It will affect all files that Babel processes. So, create a <code>.babelrc<\/code> file under the main project with this content:<\/li>\n<\/ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token string-property property\">\"presets\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">[<\/span>\r\n    <span class=\"token string\">\"react\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"env\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token string-property property\">\"plugins\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">[<\/span>\r\n    <span class=\"token string\">\"transform-export-extensions\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"transform-class-properties\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"transform-object-rest-spread\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n<span class=\"token punctuation\">}<\/span><\/code><\/pre>\n<\/div>\n<ol start=\"7\">\n<li>Create a <code>src<\/code> directory with the files <code>Control.js<\/code>, <code>Preview.js<\/code> and <code>index.js<\/code><\/li>\n<\/ol>\n<p><code>src\/Control.js<\/code><\/p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\"> <span class=\"token keyword\">import<\/span> PropTypes <span class=\"token keyword\">from<\/span> <span class=\"token string\">'prop-types'<\/span><span class=\"token punctuation\">;<\/span>\r\n <span class=\"token keyword\">import<\/span> React <span class=\"token keyword\">from<\/span> <span class=\"token string\">'react'<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n <span class=\"token keyword\">export<\/span> <span class=\"token keyword\">default<\/span> <span class=\"token keyword\">class<\/span> <span class=\"token class-name\">Control<\/span> <span class=\"token keyword\">extends<\/span> <span class=\"token class-name\">React<span class=\"token punctuation\">.<\/span>Component<\/span> <span class=\"token punctuation\">{<\/span>\r\n   <span class=\"token keyword\">static<\/span> propTypes <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">{<\/span>\r\n     <span class=\"token literal-property property\">onChange<\/span><span class=\"token operator\">:<\/span> PropTypes<span class=\"token punctuation\">.<\/span>func<span class=\"token punctuation\">.<\/span>isRequired<span class=\"token punctuation\">,<\/span>\r\n     <span class=\"token literal-property property\">forID<\/span><span class=\"token operator\">:<\/span> PropTypes<span class=\"token punctuation\">.<\/span>string<span class=\"token punctuation\">,<\/span>\r\n     <span class=\"token literal-property property\">value<\/span><span class=\"token operator\">:<\/span> PropTypes<span class=\"token punctuation\">.<\/span>node<span class=\"token punctuation\">,<\/span>\r\n     <span class=\"token literal-property property\">classNameWrapper<\/span><span class=\"token operator\">:<\/span> PropTypes<span class=\"token punctuation\">.<\/span>string<span class=\"token punctuation\">.<\/span>isRequired<span class=\"token punctuation\">,<\/span>\r\n   <span class=\"token punctuation\">}<\/span>\r\n\r\n   <span class=\"token keyword\">static<\/span> defaultProps <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">{<\/span>\r\n     <span class=\"token literal-property property\">value<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">''<\/span><span class=\"token punctuation\">,<\/span>\r\n   <span class=\"token punctuation\">}<\/span>\r\n\r\n   <span class=\"token function\">render<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span>\r\n     <span class=\"token keyword\">const<\/span> <span class=\"token punctuation\">{<\/span>\r\n       forID<span class=\"token punctuation\">,<\/span>\r\n       value<span class=\"token punctuation\">,<\/span>\r\n       onChange<span class=\"token punctuation\">,<\/span>\r\n       classNameWrapper<span class=\"token punctuation\">,<\/span>\r\n     <span class=\"token punctuation\">}<\/span> <span class=\"token operator\">=<\/span> <span class=\"token keyword\">this<\/span><span class=\"token punctuation\">.<\/span>props<span class=\"token punctuation\">;<\/span>\r\n\r\n     <span class=\"token keyword\">return<\/span> <span class=\"token punctuation\">(<\/span>\r\n       <span class=\"token operator\">&lt;<\/span>input\r\n         type<span class=\"token operator\">=<\/span><span class=\"token string\">\"text\"<\/span>\r\n         id<span class=\"token operator\">=<\/span><span class=\"token punctuation\">{<\/span>forID<span class=\"token punctuation\">}<\/span>\r\n         className<span class=\"token operator\">=<\/span><span class=\"token punctuation\">{<\/span>classNameWrapper<span class=\"token punctuation\">}<\/span>\r\n         value<span class=\"token operator\">=<\/span><span class=\"token punctuation\">{<\/span>value <span class=\"token operator\">||<\/span> <span class=\"token string\">''<\/span><span class=\"token punctuation\">}<\/span>\r\n         onChange<span class=\"token operator\">=<\/span><span class=\"token punctuation\">{<\/span><span class=\"token parameter\">e<\/span> <span class=\"token operator\">=&gt;<\/span> <span class=\"token function\">onChange<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">.<\/span>target<span class=\"token punctuation\">.<\/span>value<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span>\r\n       <span class=\"token operator\">\/<\/span><span class=\"token operator\">&gt;<\/span>\r\n     <span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\r\n   <span class=\"token punctuation\">}<\/span>\r\n <span class=\"token punctuation\">}<\/span><\/code><\/pre>\n<\/div>\n<p><code>src\/Preview.js<\/code><\/p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import<\/span> PropTypes <span class=\"token keyword\">from<\/span> <span class=\"token string\">'prop-types'<\/span><span class=\"token punctuation\">;<\/span>\r\n<span class=\"token keyword\">import<\/span> React <span class=\"token keyword\">from<\/span> <span class=\"token string\">'react'<\/span><span class=\"token punctuation\">;<\/span>\r\n\r\n<span class=\"token keyword\">export<\/span> <span class=\"token keyword\">default<\/span> <span class=\"token keyword\">function<\/span> <span class=\"token function\">Preview<\/span><span class=\"token punctuation\">(<\/span><span class=\"token parameter\"><span class=\"token punctuation\">{<\/span> value <span class=\"token punctuation\">}<\/span><\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token keyword\">return<\/span> <span class=\"token operator\">&lt;<\/span>div<span class=\"token operator\">&gt;<\/span><span class=\"token punctuation\">{<\/span> value <span class=\"token punctuation\">}<\/span><span class=\"token operator\">&lt;<\/span><span class=\"token operator\">\/<\/span>div<span class=\"token operator\">&gt;<\/span><span class=\"token punctuation\">;<\/span>\r\n<span class=\"token punctuation\">}<\/span>\r\n\r\nPreview<span class=\"token punctuation\">.<\/span>propTypes <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token literal-property property\">value<\/span><span class=\"token operator\">:<\/span> PropTypes<span class=\"token punctuation\">.<\/span>node<span class=\"token punctuation\">,<\/span>\r\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">;<\/span><\/code><\/pre>\n<\/div>\n<p><code>src\/index.js<\/code><\/p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import<\/span> Control <span class=\"token keyword\">from<\/span> <span class=\"token string\">'.\/Control'<\/span>\r\n<span class=\"token keyword\">import<\/span> Preview <span class=\"token keyword\">from<\/span> <span class=\"token string\">'.\/Preview'<\/span>\r\n\r\n<span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token keyword\">typeof<\/span> window <span class=\"token operator\">!==<\/span> <span class=\"token string\">'undefined'<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span>\r\n  window<span class=\"token punctuation\">.<\/span>Control <span class=\"token operator\">=<\/span> Control\r\n  window<span class=\"token punctuation\">.<\/span>Preview <span class=\"token operator\">=<\/span> Preview\r\n<span class=\"token punctuation\">}<\/span>\r\n\r\n<span class=\"token keyword\">export<\/span> <span class=\"token punctuation\">{<\/span> Control<span class=\"token punctuation\">,<\/span> Preview <span class=\"token punctuation\">}<\/span><\/code><\/pre>\n<\/div>\n<ol start=\"8\">\n<li>Now you need to set up the locale example site. Under the main project, create a <code>dev<\/code> directory with the files <code>bootstrap.js<\/code> and <code>index.js<\/code><\/li>\n<\/ol>\n<p><code>bootstrap.js<\/code><\/p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">window<span class=\"token punctuation\">.<\/span><span class=\"token constant\">CMS_MANUAL_INIT<\/span> <span class=\"token operator\">=<\/span> <span class=\"token boolean\">true<\/span><\/code><\/pre>\n<\/div>\n<p><code>index.js<\/code><\/p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import<\/span> <span class=\"token string\">'.\/bootstrap.js'<\/span>\r\n<span class=\"token keyword\">import<\/span> <span class=\"token constant\">CMS<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span> init <span class=\"token punctuation\">}<\/span> <span class=\"token keyword\">from<\/span> <span class=\"token string\">'netlify-cms'<\/span>\r\n<span class=\"token keyword\">import<\/span> <span class=\"token string\">'netlify-cms\/dist\/cms.css'<\/span>\r\n<span class=\"token keyword\">import<\/span> <span class=\"token punctuation\">{<\/span> Control<span class=\"token punctuation\">,<\/span> Preview <span class=\"token punctuation\">}<\/span> <span class=\"token keyword\">from<\/span> <span class=\"token string\">'..\/src'<\/span>\r\n\r\n<span class=\"token keyword\">const<\/span> config <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">{<\/span>\r\n<span class=\"token literal-property property\">backend<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">{<\/span>\r\n <span class=\"token literal-property property\">name<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'test-repo'<\/span><span class=\"token punctuation\">,<\/span>\r\n <span class=\"token literal-property property\">login<\/span><span class=\"token operator\">:<\/span> <span class=\"token boolean\">false<\/span><span class=\"token punctuation\">,<\/span>\r\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n<span class=\"token literal-property property\">media_folder<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'assets'<\/span><span class=\"token punctuation\">,<\/span>\r\n<span class=\"token literal-property property\">collections<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">{<\/span>\r\n <span class=\"token literal-property property\">name<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'test'<\/span><span class=\"token punctuation\">,<\/span>\r\n <span class=\"token literal-property property\">label<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'Test'<\/span><span class=\"token punctuation\">,<\/span>\r\n <span class=\"token literal-property property\">files<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">{<\/span>\r\n   <span class=\"token literal-property property\">file<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'test.yml'<\/span><span class=\"token punctuation\">,<\/span>\r\n   <span class=\"token literal-property property\">name<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'test'<\/span><span class=\"token punctuation\">,<\/span>\r\n   <span class=\"token literal-property property\">label<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'Test'<\/span><span class=\"token punctuation\">,<\/span>\r\n   <span class=\"token literal-property property\">fields<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">[<\/span>\r\n     <span class=\"token punctuation\">{<\/span> <span class=\"token literal-property property\">name<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'test_widget'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token literal-property property\">label<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'Test Widget'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token literal-property property\">widget<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">'test'<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span>\r\n   <span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n<span class=\"token punctuation\">}<\/span>\r\n\r\n<span class=\"token constant\">CMS<\/span><span class=\"token punctuation\">.<\/span><span class=\"token function\">registerWidget<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">'test'<\/span><span class=\"token punctuation\">,<\/span> Control<span class=\"token punctuation\">,<\/span> Preview<span class=\"token punctuation\">)<\/span>\r\n\r\n<span class=\"token function\">init<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">{<\/span> config <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/code><\/pre>\n<\/div>\n<h3 id=\"development\">Development<\/h3>\n<p>To run a copy of Netlify CMS with your widget for development, use the start script:<\/p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">npm start<\/code><\/pre>\n<\/div>\n<p>Your widget source is in the <code>src<\/code> directory, where there are separate files for the <code>Control<\/code> and <code>Preview<\/code> components.<\/p>\n<h3 id=\"production--publishing\">Production &amp; Publishing<\/h3>\n<p>You&#8217;ll want to take a few steps before publishing a production built package to npm:<\/p>\n<ol>\n<li>Customize <code>package.json<\/code> with details for your specific widget, e.g. name, description, author, version, etc.\n<div class=\"gatsby-highlight\" data-language=\"json\">\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{<\/span>\r\n  <span class=\"token property\">\"name\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"netlify-cms-widget-starter\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"description\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"A boilerplate for creating Netlify CMS widgets.\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"author\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"name of developer\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"keywords\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token punctuation\">[<\/span>\r\n    <span class=\"token string\">\"netlify\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"netlify-cms\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"cms\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"widget\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"starter\"<\/span><span class=\"token punctuation\">,<\/span>\r\n    <span class=\"token string\">\"boilerplate\"<\/span>\r\n  <span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token property\">\"version\"<\/span><span class=\"token operator\">:<\/span> <span class=\"token string\">\"0.0.1\"<\/span><span class=\"token punctuation\">,<\/span>\r\n  <span class=\"token comment\">\/\/ ... rest<\/span>\r\n<span class=\"token punctuation\">}<\/span><\/code><\/pre>\n<\/div>\n<\/li>\n<li>For discoverability, ensure that your package name follows the pattern <code>netlify-cms-widget-&lt;name&gt;<\/code>.<\/li>\n<li>Delete this <code>README.md<\/code>, rename <code>README_TEMPLATE.md<\/code> to <code>README.md<\/code>, and update the new file for your specific widget.<\/li>\n<li>Rename the exports in <code>src\/index.js<\/code>. For example, if your widget is <code>netlify-cms-widget-awesome<\/code>, you would do:<\/li>\n<\/ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">if<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token keyword\">typeof<\/span> window <span class=\"token operator\">!==<\/span> <span class=\"token string\">'undefined'<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token punctuation\">{<\/span>\r\n  window<span class=\"token punctuation\">.<\/span>AwesomeControl <span class=\"token operator\">=<\/span> Control\r\n  window<span class=\"token punctuation\">.<\/span>AwesomePreview <span class=\"token operator\">=<\/span> Preview\r\n<span class=\"token punctuation\">}<\/span>\r\n\r\n<span class=\"token keyword\">export<\/span> <span class=\"token punctuation\">{<\/span> Control <span class=\"token keyword\">as<\/span> AwesomeControl<span class=\"token punctuation\">,<\/span> Preview <span class=\"token keyword\">as<\/span> AwesomePreview <span class=\"token punctuation\">}<\/span><\/code><\/pre>\n<\/div>\n<ol start=\"5\">\n<li>Optional: customize the component and file names in <code>src<\/code>.<\/li>\n<li>If you haven&#8217;t already, push your repo to your GitHub account so the source available to other developers.<\/li>\n<li>Create a production build, which will be output to <code>dist<\/code>:<\/li>\n<\/ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">npm run build<\/code><\/pre>\n<\/div>\n<ol start=\"8\">\n<li>Finally, if you&#8217;re sure things are tested and working, publish!<\/li>\n<\/ol>\n<div class=\"gatsby-highlight\" data-language=\"javascript\">\n<pre class=\"language-javascript\"><code class=\"language-javascript\">npm publish<\/code><\/pre>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>The NetlifyCMS exposes a window.CMS a global object that you can use to register custom widgets, previews, and editor plugins. The same object is also the default export if you import Netlify CMS as an npm module. The available widget extension methods are: registerWidget: registers a custom widget. registerEditorComponent: adds a block component to the &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.netlifycms.org\/docs\/custom-widgets\/\" class=\"more-link\">Read More<span class=\"screen-reader-text\"> &#8220;Creating Custom Widgets&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[3],"tags":[40,6,41],"class_list":["post-111","post","type-post","status-publish","format-standard","hentry","category-docs","tag-creating-custom-widgets","tag-netlify-cms","tag-register-editor"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":69,"url":"https:\/\/www.netlifycms.org\/docs\/customization\/","url_meta":{"origin":111,"position":0},"title":"Creating Custom Previews","author":"admin","date":"January 18, 2026","format":false,"excerpt":"The NetlifyCMS exposes a window.CMS global object that you can use to register custom widgets, previews and editor plugins. The available customization methods are: registerPreviewStyle: Register a custom stylesheet to use on the preview pane. registerPreviewTemplate: Registers a template for a collection. React Components inline interaction NetlifyCMS is a collection\u2026","rel":"","context":"In &quot;Docs&quot;","block_context":{"text":"Docs","link":"https:\/\/www.netlifycms.org\/category\/docs\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":87,"url":"https:\/\/www.netlifycms.org\/docs\/architecture\/","url_meta":{"origin":111,"position":1},"title":"Architecture","author":"admin","date":"March 28, 2026","format":false,"excerpt":"Netlify CMS is a React application, using Redux for state management with immutable data structures (immutable.js). The core abstractions for content editing are collections, entries, and widgets. Each collection represents a collection of entries. This can either be a collection of similar entries with the same structure, or a set\u2026","rel":"","context":"In &quot;Docs&quot;","block_context":{"text":"Docs","link":"https:\/\/www.netlifycms.org\/category\/docs\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":6,"url":"https:\/\/www.netlifycms.org\/htblog\/2019\/07\/netlify-cms-gatsby-plugin-4-0-0","url_meta":{"origin":111,"position":2},"title":"React Hooks support in Netlify CMS (and the Gatsby plugin)","author":"admin","date":"July 23, 2019","format":false,"excerpt":"Netlify CMS is an extensible app written in, and bundled with, React. The most common extension is the custom preview template, which allows the preview on the right side of the editor to show what the site will actually look like as you type. These preview templates are also written\u2026","rel":"","context":"In &quot;Blog&quot;","block_context":{"text":"Blog","link":"https:\/\/www.netlifycms.org\/category\/blog\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":36,"url":"https:\/\/www.netlifycms.org\/docs\/intro\/","url_meta":{"origin":111,"position":3},"title":"Intro","author":"admin","date":"April 1, 2026","format":false,"excerpt":"Overview Netlify CMS is an open source content management system for your Git workflow that enables you to provide editors with a friendly UI and intuitive workflows. You can use it with any static site generator to create faster, more flexible web projects. Content is stored in your Git repository\u2026","rel":"","context":"In &quot;Docs&quot;","block_context":{"text":"Docs","link":"https:\/\/www.netlifycms.org\/category\/docs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.netlifycms.org\/wp-content\/uploads\/2026\/04\/netlifycms.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":75,"url":"https:\/\/www.netlifycms.org\/docs\/uploadcare\/","url_meta":{"origin":111,"position":4},"title":"Uploadcare","author":"admin","date":"December 18, 2025","format":false,"excerpt":"Uploadcare is a sleek service that allows you to upload files without worrying about maintaining a growing collection \u2014 more of an asset store than a library. Just upload when you need to, and the files are hosted on their CDN. They provide image processing controls from simple cropping and\u2026","rel":"","context":"In &quot;Docs&quot;","block_context":{"text":"Docs","link":"https:\/\/www.netlifycms.org\/category\/docs\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":10,"url":"https:\/\/www.netlifycms.org\/blog\/2019\/06\/implementing-a-jekyll-cms-in-3-days","url_meta":{"origin":111,"position":5},"title":"Implementing a Jekyll CMS in 3 Days","author":"admin","date":"June 6, 2019","format":false,"excerpt":"This guest post was written by Shea Daniels, Lead Software Engineer at Dwolla and user of Netlify CMS. It was originally published on the Dwolla blog. Let\u2019s say you\u2019re building the next great startup or putting together a spectacular event\u2014the first question anybody asks you is \u201cWhat\u2019s the website?\u201d A\u2026","rel":"","context":"In &quot;Blog&quot;","block_context":{"text":"Blog","link":"https:\/\/www.netlifycms.org\/category\/blog\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.netlifycms.org\/wp-content\/uploads\/2019\/06\/Screen-Shot-2019-06-06-at-10.33.31-AM.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.netlifycms.org\/wp-content\/uploads\/2019\/06\/Screen-Shot-2019-06-06-at-10.33.31-AM.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.netlifycms.org\/wp-content\/uploads\/2019\/06\/Screen-Shot-2019-06-06-at-10.33.31-AM.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.netlifycms.org\/wp-content\/uploads\/2019\/06\/Screen-Shot-2019-06-06-at-10.33.31-AM.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.netlifycms.org\/wp-content\/uploads\/2019\/06\/Screen-Shot-2019-06-06-at-10.33.31-AM.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/www.netlifycms.org\/wp-content\/uploads\/2019\/06\/Screen-Shot-2019-06-06-at-10.33.31-AM.png?resize=1400%2C800&ssl=1 4x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.netlifycms.org\/wp-json\/wp\/v2\/posts\/111","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.netlifycms.org\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.netlifycms.org\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.netlifycms.org\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.netlifycms.org\/wp-json\/wp\/v2\/comments?post=111"}],"version-history":[{"count":2,"href":"https:\/\/www.netlifycms.org\/wp-json\/wp\/v2\/posts\/111\/revisions"}],"predecessor-version":[{"id":113,"href":"https:\/\/www.netlifycms.org\/wp-json\/wp\/v2\/posts\/111\/revisions\/113"}],"wp:attachment":[{"href":"https:\/\/www.netlifycms.org\/wp-json\/wp\/v2\/media?parent=111"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.netlifycms.org\/wp-json\/wp\/v2\/categories?post=111"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.netlifycms.org\/wp-json\/wp\/v2\/tags?post=111"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}