Discussion on rendering PortableText with images and creating custom annotations for color in a React app using Sanity.

7 replies
Last updated: Apr 19, 2023
So, I'm trying to render a PortableText with images in a React application (using @portabletext/react and Sanity v3). I have followed the ReadMe on how to create a custom react component to display images, but the BlockContent returned from my query contains objects of images with a reference to the
instead of the expanded image url. How can I get the expanded image references directly from my GROQ query?
In other queries I can do
*[_type == "post"] { "image": image.asset->url }
but I'm not sure how to do this for BlockContent.
This is the blog template without any big modifications.
Jan 21, 2023, 3:22 PM
My query
Jan 21, 2023, 3:26 PM
The data returned
Jan 21, 2023, 3:27 PM
Of course I find the answer immediately after asking the question πŸ˜„ https://www.sanity.io/help/block-content-image-materializing
But then I have a follow-up question: The query suggested in the article includes the
property for all blocks with
as value if the source block does not contain the
property. Is there a way to only include the "asset"-property in the result for blocks that definitely contains an
Jan 21, 2023, 3:43 PM
Never mind, figured out that as well... Oh, the wonders of rubber ducking oneself.... 🀣
Jan 21, 2023, 3:51 PM
This is delightful to read πŸ™‚ If you want some πŸ’… for your portable text, you should look at these:β€’
inline blocks β€’
custom annotations and more
Jan 23, 2023, 3:44 PM
user J
Thanks for those links! πŸ˜„ I already made a youtube embed following one of the guides on the website. Pretty cool! Didn't know you could have those kind of inline blocks as well
Jan 25, 2023, 8:47 AM
Nice ones, I had really hoped for an complete example of how to create an annotation component for color because I can not get it to work render the selected color πŸ˜•
the custom color picker stores the color in correct way, like

      "_type": "block",
      "children": [
          "_key": "6dce5ea4c2d4",
          "_type": "span",
          "marks": [
          "text": "I want to set color on this text!"
      "markDefs": [
          "_key": "021bc167e2d2",
          "_type": "color",
          "color": "rgb(0, 113, 119)"
My custom TextColor component set to components: { annotation: TextColor } in Block schema

const InlineAnnotation = styled.span`
  border: none;
  ${(props) => props.textColor};

const TextColor = (props) => {
  const { value, renderDefault } = props
  const { color } = value
  console.log(value, color)

  return (
      textColor={{ color }}
      {renderDefault({ ...props })}
console.log, where we see that it actually pickup selected color.

{_key: '021bc167e2d2', _type: 'color', color: 'rgb(0, 113, 119)'} 'rgb(0, 113, 119)'
{_key: 'a0f14ee6a1c6', _type: 'color', color: 'rgb(249, 93, 122)'} 'rgb(249, 93, 122)'
renders in portableText UI

<span class="sc-dOrDzm hSVqgX MyCustomAnnotatianWhereColorIsSet">
  <span class="sc-eyLAWx erPojB">
    <span data-annotation="">
      <span data-slate-string="true">
        here is the next text for color!
But the .erPoJB class comes from built in <Annotation> with below css and I have no idea how to solve this. , to not render dashed bottom border nor setting the color
  -webkit-text-decoration: none;
  text-decoration: none;
  display: inline;
  background-color: #fff;
  border-bottom: 1px dashed #565d67;
  color: #565d67;
for reference, β€œmy” .hSVqgX got below css:

border: none;
color: rgb(249,93,122);
The portableBlock component in the studio looks like first screen shot

Could you please give me a hint how to render the texts colors in the β€œRTE”?
user J
(In V2 we just used the blockedEditor in the block content schema, very simple and just worked
blockEditor: {
  render: ({ color, children }) => {
    return (
      <span style={{ color }}>{children}</span>
Apr 19, 2023, 1:47 PM

Sanity– build remarkable experiences at scale

The Sanity Composable Content Cloud is the 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?