Auto-apply bold mark decorator when selecting heading styles in Portable Text

18 replies
Last updated: Nov 2, 2021
Hey Everyone,
I have a question around Portable Text and marks. We current have our Header stylings setup with a bolded font-weight. We are wondering if, upon selecting a heading style that has a bolded font weight, we can programmatically apply mark decorators to the same text so we can show that the text is bolded?
AI Update

Unfortunately, you can't programmatically apply mark decorators (like strong) when a heading style is selected in the Portable Text editor. Marks and block styles are intentionally separate concepts in Portable Text, and there's no built-in mechanism to automatically link them together. This separation is by design—it keeps your content structure flexible and prevents coupling presentation logic to content structure.

The Right Solution: Customize Block Style Rendering

The best approach is to customize how heading styles appear in the editor using the component property. This gives your content editors a visual representation that matches your front-end styling without actually modifying the underlying data:

import React from 'react'

const BoldHeadingStyle = (props) => (
  <span style={{ fontWeight: 'bold' }}>{props.children}</span>
)

export default {
  name: 'content',
  type: 'array',
  of: [
    {
      type: 'block',
      styles: [
        { title: 'Normal', value: 'normal' },
        { 
          title: 'Heading 1', 
          value: 'h1',
          component: BoldHeadingStyle
        },
        { 
          title: 'Heading 2', 
          value: 'h2',
          component: BoldHeadingStyle
        },
        // ... more heading styles
      ]
    }
  ]
}

This approach keeps your data clean (no redundant strong marks on headings) while giving content editors a WYSIWYG experience that matches your front-end rendering. You can see a complete example of customizing block styles in the official documentation on customizing the Portable Text Editor.

Why This Matters

Keeping marks and block styles separate actually gives you more flexibility:

  • Clean data: Your headings don't carry redundant bold marks that duplicate their inherent styling
  • Multi-platform rendering: The same content can render appropriately across web, mobile, and other platforms
  • Easier maintenance: You can change heading styles globally without needing to update mark data

Alternative: Create Style Variations

If you genuinely need both bold and non-bold versions of headings as distinct options, you can create separate style definitions:

styles: [
  { title: 'Normal', value: 'normal' },
  { 
    title: 'H2', 
    value: 'h2',
    component: (props) => <h2>{props.children}</h2>
  },
  { 
    title: 'H2 Bold', 
    value: 'h2Bold',
    component: (props) => <h2 style={{ fontWeight: 'bold' }}>{props.children}</h2>
  },
]

Then handle both values appropriately in your front-end serializer. Remember, the value property is just a connector between Studio and your output—it doesn't have to be a semantic HTML element name.

The component customization gives you complete control over the visual presentation in the editor while maintaining the architectural benefits of Portable Text's structured approach. This is the recommended way to show editors that text is bolded when using heading styles with bold font-weight, without programmatically applying strong mark decorators to the underlying data.

Show original thread
18 replies
Since it’s bold already, there’s no difference to show.
However, if you write a serializer you can decide a bold header means whatever you want…
https://www.sanity.io/docs/presenting-block-text#ac67a867dd69
Yeah..... The idea solution would be for a us to create the Heading style without it being a bold font weight and then have them bold it as a choice. But.... clients haha.
What we are really trying to achieve is simply aligning the CMS with the front end. So that a header that is 50px and bold shows as that in the editor. (Only in the editor, the front end works perfectly).
You can just set the font-weight of h1, h2, etc to “normal” in CSS and use bold as normal.
Hey Josh, I might not be explaining it very clearly. We have essentially shot ourselves in the foot by setting up the serialiser on the front end with a different style than what is displaying in the Portable text editor.
But I have just found that we can extend the styles field in sanity to include block editor rendering block. so I think this will solve it 🙂
Thanks for your prompt reply too mate
It sounds like you may have a solution already, but are you saying you want an
h3
to also have
strong
applied to it in the studio?
Hey Geoff. Yes pretty much exactly that. We just want the Studio editor to mirror the front end styles.
So another, perhaps future example, could be that a style is not "h1" but "title" and a "title" style has bold, italics and a different font. It would be great to display all of this inside the portable text field in Sanity. Which I think the what extending the rendering block should be able to do? e.g


...
Yes, you’re absolutely right and there’s nothing tying you to using semantic element names (as we see with
normal
, for example). The
value
is really just a connector between your studio and your output (e.g., your serializer on the front end). You could even do variations like:

export default {
  name: "content",
  title: "Content",
  type: "array",
  of: [
    {
      type: "block",
      styles: [
        { title: "Normal", value: "normal" },
        // ...,
        { title: "H3", value: "h3" },
        { title: "H3 Strong", value: "h3Strong", blockEditor: { render: ({ children }) => <h3><strong>{children}</strong></h3> } },
    // ...,
    },
  ]
}

Yes, you’re absolutely right and there’s nothing tying you to using semantic element names (as we see with
normal
, for example). The
value
is really just a connector between your studio and your output (e.g., your serializer on the front end). You could even do variations like:

export default {
  name: "content",
  title: "Content",
  type: "array",
  of: [
    {
      type: "block",
      styles: [
        { title: "Normal", value: "normal" },
        // ...,
        { title: "H3", value: "h3" },
        { title: "H3 Strong", value: "h3Strong", blockEditor: { render: ({ children }) => <h3><strong>{children}</strong></h3> } },
    // ...,
    },
  ]
}

Thanks
user A
! That's great. We Might submit a few code snippets into the community after this project with some of the stuff we have been doing around portable text which is pretty exciting.
Thanks again for your help
Oh
user A
one more question, unrelated to portable text. When creating a document preview, is it possible to grab the published status of a document? One of our clients is looking for a way to change the icon if a document is a draft vs published.
If you’re on a recent enough version of the studio, those indications are there already. Would that suffice or are you looking to do something different with the statuses?
If you’re on a recent enough version of the studio, those indications are there already. Would that suffice or are you looking to do something different with the statuses?
Hey Geoff, we were looking to do something a bit more visual as our client is looking to quickly identify drafts amongst a lot of content. Although I am aware drafts also automatically appear at the top of the documents list as well.Not a super high priority for us. We have just found it useful for clients, when populating or migrating content into Sanity for the first time, to add some visual symbols for when content is still missing e.g a recipe missing ingredients will have a certain emoji in the preview. Having the draft vs published status would just allow us to create another layer of context to this system.
You can use async in
media
inside
preview.prepare()
, which might give you a bit more capability (vs. adding something to the
title
or
subtitle
, for example). I’ll try to think more about this and/or ask a colleague and will get back to you.
Thanks Geoff. Yeah we are using the media section to sometimes add regional flags or big red x / green tick images haha. Thanks for checking in with your colleague 🙂
Thanks Geoff. Yeah we are using the media section to sometimes add regional flags or big red x / green tick images haha. Thanks for checking in with your colleague 🙂

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.

Was this answer helpful?