Issue with creating a custom annotation in Portable Text in JavaScript.

22 replies
Last updated: May 7, 2020
this is probably a dumb JS question, but i'm running into an issue while trying to create my own custom
annotation
for Portable Text.
i'm attempting to create my own data-attribute, and the content is passing in just fine, but when i try to add it to my mark, it just errors out.

here's my code:

customLink: ({ mark, children}) => {
      const { dataAttribute, attributeValue } = mark
      const customAttribute = (dataAttribute && attributeValue) ? `data-${dataAttribute}="${attributeValue}"` : ''
      
      return <span {customAttribute} className={`rainbow`} >{children}</span>
    }
and the error is
29:43  error  Parsing error: Unexpected token, expected "..."
AI Update

This isn't a dumb question at all! The issue you're running into is actually a JSX syntax error, not specific to Sanity's Portable Text.

The problem is that you can't use string interpolation to create JSX attributes like {customAttribute}. In JSX, you need to pass attributes as actual properties, not as strings.

Here's the corrected code:

customLink: ({ mark, children }) => {
  const { dataAttribute, attributeValue } = mark
  
  // Create a dynamic attribute object
  const customAttributes = (dataAttribute && attributeValue) 
    ? { [`data-${dataAttribute}`]: attributeValue }
    : {}
  
  return (
    <span {...customAttributes} className="rainbow">
      {children}
    </span>
  )
}

What's happening here:

  • You're creating an object with a computed property name using [data-${dataAttribute}]
  • Then you're spreading that object into the <span> element using {...customAttributes}
  • This properly passes the attribute to React/JSX

Alternatively, if you always want to add the data attribute (even if empty), you can do:

customLink: ({ mark, children }) => {
  const { dataAttribute, attributeValue } = mark
  
  return (
    <span 
      {...(dataAttribute && attributeValue && { [`data-${dataAttribute}`]: attributeValue })}
      className="rainbow"
    >
      {children}
    </span>
  )
}

The key takeaway: In JSX, you can't pass HTML attributes as strings. You need to either use the spread operator with an object ({...obj}) or pass individual props directly.

i tried adding the spread
...
but that causes a different error
so how do i pass this variable into my return?
which line is line 29?
user S
its the return
it doesn't like the
{customAttribute}
ah!
try something like this:
const customLink = ({ mark, children }) => { 
    const { dataAttribute, attributeValue } = mark
    const attribute = { [dataAttribute]: attributeValue };
    return (
        <span {...attribute} className='rainbow'>{children}</span>
    );
};   
that works to clear the error, but doesn't return my desired output...
returns
toggle="wonderful-things"

want
data-toggle="wonderful-things"
so just need to add the
data-
prefix
ah ok 1 sec
something like this:
const customLink = ({ mark, children }) => { 
    const { dataAttribute, attributeValue } = mark
    const attribute = { ['data-'+dataAttribute]: attributeValue };
    return (
        <span {...attribute} className='rainbow'>{children}</span>
    );
};    
that works a treat! thank you! 🙏
awesome! :party_parrot:
for future reference, what was i doing incorrectly?
I think you needed to convert it to a key:value object to spread it
that makes sense...
still find it odd that just the regular
{var}
way wasn't working
yeah, in react it wants a thing, and then wants to attach a value/property to said thing
I dont think it’s like PHP where you can just echo out values
(ie a string)

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?