Issue with customizing portable text editor in Sanity v3 resolved with version update.
I can see your code structure is actually correct according to the official Sanity documentation! The pattern of using icon and component directly on the decorator object is the right approach for Sanity v3. However, there are a few things that might be causing issues. Let me help you troubleshoot:
Your code structure is correct, but here are some common issues and solutions:
1. Import React properly
Make sure you have React imported at the top of your file since you're using JSX:
import React from 'react'2. Icon component needs to return valid JSX
Your icon function should return a proper React element. Try this:
{
title: 'Highlight',
value: 'highlight',
icon: () => <span style={{fontWeight: 'bold'}}>H</span>,
component: (props: any) => (
<span style={{ backgroundColor: 'yellow' }}>{props.children}</span>
),
}3. Alternative: Use a proper icon from @sanity/icons
Instead of an inline function, you could import an icon from the @sanity/icons package:
import { HighlightIcon } from '@sanity/icons'
// Then in your decorator:
{
title: 'Highlight',
value: 'highlight',
icon: HighlightIcon,
component: (props: any) => (
<span style={{ backgroundColor: 'yellow' }}>{props.children}</span>
),
}4. Complete working example
Here's a complete working example based on the official documentation:
import React from 'react'
const HighlightIcon = () => (
<span style={{ fontWeight: 'bold' }}>H</span>
)
const HighlightDecorator = (props: any) => (
<span style={{ backgroundColor: 'yellow' }}>{props.children}</span>
)
export default {
title: "Titre du block",
name: "titleBlock",
type: "array",
of: [{
type: "block",
marks: {
decorators: [
{ title: "Strong", value: "strong" },
{ title: "Emphasis", value: "em" },
{ title: "Code", value: "code" },
{ title: "Underline", value: "underline" },
{ title: "Strike", value: "strike-through" },
{
title: 'Highlight',
value: 'highlight',
icon: HighlightIcon,
component: HighlightDecorator,
}
],
}
}],
group: "text",
validation: (Rule: any) => Rule.required(),
}5. Regarding TypeScript/TSX files
You're absolutely right to use .tsx files! Sanity v3 works perfectly with TypeScript. The documentation examples use .js for simplicity, but .tsx is actually the recommended approach for type safety. This is not causing your issue.
6. Restart your dev server
After making schema changes, make sure to restart your Sanity Studio dev server:
npm run devor if you're using the newer commands:
npx sanity devCommon troubleshooting steps:
- Check your browser console for any error messages - this is crucial for understanding what's going wrong
- Make sure you're on Sanity Studio v3 (check your
package.jsonforsanityversion) - Clear your browser cache and hard refresh (Ctrl+Shift+R or Cmd+Shift+R)
- Try upgrading Sanity if you're on an older v3 version:
npx sanity upgrade
Possible issues based on the pattern:
Without seeing the picture you mentioned, the most common issues are:
- Icon not showing: This usually means the icon component isn't returning valid JSX or React isn't imported
- Styling not applying: Make sure the
componentprop receives and rendersprops.children - Button not appearing: Check if all decorators are showing or just the custom one is missing
The pattern you're using matches the official documentation exactly, so if it's still not working after these adjustments, please share any error messages from the console and I can help further! 🙏
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.