Creating a Margin Action with Decorator in Sanity Block Editor
Creating a Margin Action in Sanity's block editor to apply decorators is a bit tricky because the Portable Text Editor doesn't have a built-in API specifically for "margin actions" that apply decorators to entire blocks. However, I can guide you through the closest approaches to achieve what you're looking for.
Understanding the Challenge
Decorators in Sanity's Portable Text are designed to work on inline text selections, not entire blocks. They're simple string-based formatting marks like bold, italic, or custom styles applied to spans of text. This means you can't directly apply a decorator to a whole block from a margin button in the traditional sense.
Recommended Approaches
Option 1: Use Custom Block Styles (Best for Block-Level Comments)
Instead of decorators, use custom block styles which apply to entire blocks. This is more semantically correct for your use case:
import {defineType} from 'sanity'
import {CommentIcon} from '@sanity/icons'
export default defineType({
name: 'blockContent',
type: 'array',
of: [
{
type: 'block',
styles: [
{title: 'Normal', value: 'normal'},
{title: 'Heading 1', value: 'h1'},
// Your custom comment style
{
title: 'Commented',
value: 'commented',
icon: CommentIcon
}
]
}
]
})Users can then select a block and change its style from the style dropdown in the toolbar. While this isn't a margin button, it achieves block-level marking.
Option 2: Use Annotations with Metadata
For actual commenting functionality where you want to store comment text, use annotations instead of decorators. Annotations can carry additional data:
marks: {
annotations: [
{
name: 'comment',
type: 'object',
title: 'Comment',
icon: CommentIcon,
fields: [
{
name: 'text',
type: 'text',
title: 'Comment Text'
},
{
name: 'author',
type: 'string',
title: 'Author'
}
]
}
]
}This allows users to highlight text and add comments with metadata, which is more powerful than simple decorators.
Option 3: Custom Block Type with Comment Field
For true block-level commenting, create a wrapper block type:
{
name: 'commentedBlock',
type: 'object',
title: 'Block with Comment',
fields: [
{
name: 'content',
type: 'block',
title: 'Content'
},
{
name: 'comment',
type: 'text',
title: 'Comment'
}
]
}Then include this in your block content array:
of: [
{type: 'block'},
{type: 'commentedBlock'}
]Why Margin Actions for Decorators Don't Exist
The Portable Text Editor's architecture separates concerns: decorators operate on text selections (controlled by the user highlighting text), while block-level operations use styles or custom block types. There isn't a built-in "margin action" API that bridges these two concepts because it would be semantically confusingādecorators are meant for inline formatting, not block-level metadata.
If you absolutely need a custom UI button in the margin area, you'd need to create a custom Studio plugin with significant custom React components that hook into the Portable Text Editor's internal APIs, which is quite advanced and not officially documented for this specific use case.
Recommendation
For a commenting feature on blocks, I'd strongly recommend Option 2 (annotations) if you want inline comments, or Option 1 (custom block styles) if you just need to visually mark entire blocks as "commented" without storing additional data. Both work with the editor's existing UI patterns and don't require custom margin buttons.
Show original thread6 replies
Sanity ā Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.