Unlock seamless workflows and faster delivery with our latest releases - Join the deep dive

Creating a margin action to add a decorator to a block in Sanity's block editor.

6 replies
Last updated: Feb 28, 2022
Hi all! Does anyone know how you'd go about creating a Margin Action in the block editor that applies a decorator to the current block? I'm trying to create a button in the margin that will allow the user to add a "comment" on a block-by-block basis:
Feb 24, 2022, 5:29 PM
The example in the docs (https://www.sanity.io/docs/customization#7c452491a5f2 ) shows how to insert a new text block after the current block, rather than customising the current block (in this case applying a decorator). Can anyone help me?
This is my margin action:

// BlockMarginCommentAction.js
import React from "react";
import { Button } from "@sanity/ui";
import { CommentIcon } from "../../styles/Icons";

function BlockMarginCommentAction(props) {
    const handleClick = (event) => {
        const { insert, set, block, value } = props;
        insert([
            {
                _type: "block",
                children: [
                    {
                        _type: "span",
                        text: "New text block!",
                    },
                ],
            },
        ]);
        // Instead of inserting a new block, add a decorator to the current block?
    };
    return (
        <Button
            icon={CommentIcon}
            padding={2}
            onClick={handleClick}
            title="Add a comment to this block."
            mode="bleed"
        />
    );
}

export default BlockMarginCommentAction;
And this is the decorator I'm trying to apply:

import { CommentIcon } from "../../styles/Icons";

export default {
    name: "blockComment",
    title: "Comment",
    type: "object",
    icon: CommentIcon,
    options: {
        editModal: "dialog",
    },
    fields: [
        {
            name: "comment",
            title: "Comment",
            type: "text",
        },
        {
            name: "reference",
            title: "Reference to page:",
            type: "reference",
            to: [{ type: "page" }],
        },
    ],
};

Feb 24, 2022, 5:30 PM
This is a tricky one, but you'd have to use the
set
function to set the current block to a block that has the correct
markDefs
. For example:
const handleClick = () => {
    const id = uuid()

    set({
      ...block,
      markDefs: [
        { 
          _type: 'blockComment',  
          _key: id,
          comment:'this is a comment',
        }
      ],
      children: [
        {
          ...block.children[0],
          marks: [ id ]
        }
      ]
    })
  }
However, allowing an editor to control what
markDefs.comment
contains through a component will be quite tricky. You can't use something like
useState
to open a modal or popup because hooks are not allowed within the Portable Text Editor.
Feb 24, 2022, 9:56 PM
Hey Racheal, thanks so much for looking at this! Your example is exactly what I was trying to accomplish. Hopefully hooks might be allowed in the future, as it would be nice to trigger a popup after the margin action is pressed šŸ¤ž
Feb 28, 2022, 1:42 PM
Hey Racheal, thanks so much for looking at this! Your example is exactly what I was trying to accomplish. Hopefully hooks might be allowed in the future, as it would be nice to trigger a popup after the margin action is pressed šŸ¤ž
Feb 28, 2022, 1:42 PM
It would be super powerful to be able to have this functionality!
Feb 28, 2022, 5:32 PM
It would be super powerful to be able to have this functionality!
Feb 28, 2022, 5:32 PM

Sanityā€“ build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?