Having trouble with custom Netlify widgets

I’d like to make some custom widgets for Netlify CMS. I’m using webpack/eleventy.
The problem I’m having is, once I save the entry or switch from Rich Text/Markdown the widget UI stops working.

This is a dummy example. Let’s say I have two fields and I want to output some HTML from it.

CMS.registerEditorComponent({
  id: "header",
  label: "header",
  fields: [
    { name: 'heading', label: 'heading', widget: 'string' },
    { name: 'text', label: 'text', widget: 'string' }
  ],
  // This is a dummy regex pattern
  pattern: /^.*>$/,
  // I need to return the matching fields from the toBlock function.
  fromBlock: function (match) {
    return {
      heading: match[1],
      text: match[2]
    };
  },
  // What renders on the block editor
  toBlock: function (obj) {
    return `<h1>${obj.heading}</h1>\n<p>${obj.text}</p>`;
  },
  // What renders on the preview window
  toPreview: function (obj) {
    return `<h1>${obj.heading}</h1>\n<p>${obj.text}</p>`;
  }
});

The regex pattern is not always going to work for more complex widgets with 3-5 different elements, this could be text or images.

Is there a way to do something like this instead

  fromBlock: function (obj) {
    return {
      heading: obj.heading,
      text: obj.text
    };
  },

Am I just doing things the wrong way?. I’d appreciate your input a lot.

i couldn’t get this working either. it would be great if there were a couple more examples on github we could look at to figure out how this works.

Hi @brandonjhz and welcome to the community :slight_smile: Sorry for the late reply.

Since editor components are meant to be able to parse raw markdown files the pattern should be able to extract the fields from the raw content file.

There is a bit more complex example with 3 fields here:

@brandonjhz and @solomonpierce, can you share an example that isn’t working? e.g. share a content of a markdown file, the block that should be generated and parsed and the fields that you configure

I am working with the image editor component to try and create my own. I don’t really understand the toBlock portion. Here is my setup.

caption.js

import React from 'react';

const caption = {
  label: 'Image Caption',
  id: 'caption',
  fromBlock: match =>
    match && {
      caption: match[1]
    },
  toBlock: ({ caption }) =>
    `![${caption || ''}]`,
  // eslint-disable-next-line react/display-name
  toPreview: ({ caption }) => {
    return <span>{caption || ''}</span>;
  },
  pattern: /^!\[(.*)\]$/,
  fields: [
    {
      label: 'Caption',
      name: 'caption',
    },
  ],
};

export const NetlifyCmsEditorComponentCaption = caption;
export default caption;

cms.js

//Editor Components
import caption from './editor-components/caption'

//Register Editor Components
CMS.registerEditorComponent(caption)

Example working in CMS Preview.

But not on the actual post.

From what I understand toBlock is what is added to the actual post but I figured it would be similar to the image editor component by posting what is in toPreview

toBlock: ({ alt, image, title }) =>
    `![${alt || ''}](${image || ''}${title ? ` "${title.replace(/"/g, '\\"')}"` : ''})`,
// eslint-disable-next-line react/display-name
toPreview: ({ alt, image, title }, getAsset, fields) => {
    const imageField = fields?.find(f => f.get('widget') === 'image');
    const src = getAsset(image, imageField);
    return <img src={src || ''} alt={alt || ''} title={title || ''} />;
  },

I have tried copying what is in toBlock to toPreview and made adjustments to the regex pattern to capture it but that did not work either. Is there something I am missing here?

Hi there! Thanks for your interest in Netlify CMS. Looks like you posted your question a little while ago, but that you haven’t received a solution yet. Here’s where you might get more help:

netlifycms.org - the site houses our extensive documentation that likely contains helpful information to get you back on track.

netlify cms slack - join our friendly slack channel and chat with other cms pros to get the help you need.

GitHub Issues - think you’ve found a bug, or would like to make a feature request? Make your voice heard here. Netlify CMS is open source - PRs and other contributions are also welcome!

Stack Overflow Check StackOverflow for questions tagged “Netlify CMS” if you don’t get an answer in the Slack or the GH issues. StackOverflow reaches a worldwide audience of knowledgeable people.

Your question will be left open here for anyone to comment - but we encourage you to check out the above resources if you are still looking for a solution!

I think I made a separate block and called it in as a string. Looking at the question my guess is to do this.

import React from 'react';

const caption = {
  label: 'Image Caption',
  id: 'caption',
  fromBlock: match =>
    match && {
      caption: match[1]
    },
  toBlock: ({ caption }) =>
    `${caption || ''}`, //<-- I changed this! Changed from `![${caption || ''}]`,
  // eslint-disable-next-line react/display-name
  toPreview: ({ caption }) => {
    return <span>{caption || ''}</span>;
  },
  pattern: /^!\[(.*)\]$/,
  fields: [
    {
      label: 'Caption',
      name: 'caption',
    },
  ],
};

export const NetlifyCmsEditorComponentCaption = caption;
export default caption;

Been a while since I worked on this project so I don’t know if that will work.

1 Like

No worries Mate, figured it out, thanks for the reply. Works just fine.

1 Like

Thanks for coming back and sharing this, @byebyers! Happy building, @Rogelio! :rocket: