Help needed to customize a block content in Sanity to create an email link.
18 replies
Last updated: Sep 21, 2021
E
Hey everyone, I'm brand new here and brand new to web dev too. 🙂 I just deployed my first website (ericrodgers.io ) using the sanity/gatsby portfolio template. I'm trying to figure out how to customize some block content to create a link that opens email. Ideally I would like that new feature to have an email icon in the block content menu bar. So I guess this would behave like the built in "link" feature, but it would have its own icon, it would validate for email, and it would prepend the anchor tag's href with "mailto: " and maybe even append it with ?subject &/or &body default text... In the block content editor I want to be able to highlight some text that says "get in touch", click an email icon in the block content menu next to the decorator and link options, and then enter my email address, so that on the front end gatsby side of my site anyone who is visiting my page can click the "get in touch" text and it will open their email and populate the "to:" field with my address. I hope this makes sense! Thanks for your help!
Sep 15, 2021, 6:14 PM
E
Thanks so much Racheal!
Sep 15, 2021, 7:08 PM
E
I read and re-read the links you provided. I'm getting tripped up on the first step here! I was able to add a custom annotation with an icon to the block content menu bar in the Sanity UI, but it doesn't work properly. When I try to use it, the fields I've included in bioPortableText.js don't show up, it just has an unusable input field with the default text "[object Object]" inside of it. I've attached a screen capture of the UI. Here's my github repo (https://github.com/ericerodgers/portfolio ) and here's the code from bioPortableText.js:`import {MdEmail} from 'react-icons/md';`
export default {
name: 'bioPortableText',
type: 'array',
title: 'Excerpt',
of: [
{
title: 'Block',
type: 'block',
styles: [{title: 'Normal', value: 'normal'}],
lists: [],
marks: {
decorators: [
{title: 'Strong', value: 'strong'},
{title: 'Emphasis', value: 'em'},
{title: 'Code', value: 'code'}
],
annotations: [
{
name: 'link',
type: 'object',
title: 'URL',
fields: [
{
title: 'URL',
name: 'href',
type: 'url'
},
{
title: 'Open in new window',
name: 'blank',
type: 'boolean'
}
]
},
{
name: 'email',
type: 'object',
title: 'Email',
icon: MdEmail,
fields: [
{
title: 'Email address',
name: 'href',
type: 'string',
// validation from tutorial: <https://stordahl.dev/bits/sanity-email-validation>
validation: (Rule) =>
Rule.regex(`/[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/,`
{
name: 'email', // Error message is "Does not match email-pattern"
invert: false // Boolean to allow any value that does NOT match pattern
}
)
}
]
}
]
}
}
]
}
Sep 17, 2021, 4:52 PM
E
Ok after digging around in my data structure, I saw that the "_type" in the markDefs for my custom email annotation was coming through as "email", which was the "name" I gave it. Confusing to me because I thought the name was arbitrary, but it seems to affect the data type and functionality here... So in bioPortableText.js I've changed it to
name: "span", and now _type shows up as "span" and everything finally works in the Sanity UI as I'd intended, and the email I enter there is accessible on the front end via a graphql query, in the markDefs object. Don't really understand why, but it works. But now I'm having trouble figuring out how to make the serializer work. My bio is rendered as PortableText... not sure how to set up the serializer or how to include it as a prop in the PortableText component... I've read all the docs and watched all the tutorials and been all over google... please help! 😩
Sep 17, 2021, 6:21 PM
E
Ok now after a lot of trial and error I got it to work... the only remaining problem being that when I click on my email link it triggers a page load. I guess I can live with that for now.
Sep 17, 2021, 7:11 PM
E
Here's what worked for me... serializers.js now looks like this: import React from 'react';
I imported BlockContent and serializers into the my about.js page and I replaced the PortableText element with a BlockContent element that included the serializers={serializers} prop. I hacked my way through thisand I'm shocked that it works... If someone can review my code here and let me know if this is the correct way to do it I would be very appreciative! Also I'd love to solve the page reload problem... once again my repository is available here:
https://github.com/ericerodgers/portfolio . Thanks!
import {Figure} from "./figure"; const serializers = { types: { figure: Figure }, marks: { span: ({mark, children}) => { // Read <https://css-tricks.com/use-target_blank/> const { blank, href } = mark const mailto = `mailto:${href}?subject="Hi!"&body="I love your website!"` return ( <a href={mailto} target="_blank" rel="noopener">{children}</a> ) }, link: ({mark, children}) => { const { blank, href } = mark return blank ? ( <a href={href} target="_blank" rel="noopener noreferrer"> {children} </a> ) : ( <a href={href}>{children}</a> ) } } }; export default serializers;
https://github.com/ericerodgers/portfolio . Thanks!
Sep 17, 2021, 7:21 PM
Hey Eric! Great progress! I wasn't able to take a look at this thread until now, since I was out sick for a few days. Super impressed with your ability to work through this! I was curious about you having to change the name of your custom object to 'span'. You should be able to use whatever name you'd like for the object, so long it matches the name under
Also, just a guess, but I think if you disable
marksin your serializers. For example, if you named the object 'email', the serializer would have to be named 'email'. Did you not experience that behavior?
Also, just a guess, but I think if you disable
target='_blank'you can stop the page from refreshing, but I could be wrong!
Sep 18, 2021, 5:38 PM
E
Hey Racheal! Thanks for circling back on this. Hope you're feeling better. You were right about disabling target='_blank', that has stopped the page refresh when the email link is clicked! As for the custom object name in bioPortableText.js, I have gone back and tinkered with it again. As soon as I change the name from "span" back to "email" (or to anything else) and refresh the Sanity UI in my local build environment, the input field becomes disabled, and has default text that says: [object, Object]. name: 'span' is the only thing that gets it to work in my Sanity UI. This happens whether or not I match the new name with the name in the serializers.js file in my web (gatsby) folder. Looks to me like a bug, but I'm very new to web dev and 99.99% of the time things are going wrong for me it's my fault! Have you tried forking my repo and running it locally to see if it works like that for you?
Sep 20, 2021, 9:59 PM
I was able to clone your repo, but the annotation is behaving as it should be. One issue you might be running into is that it turns out that
When I intentionally tried to break it, I couldn't get the behavior you do. The only thing that happened was the modal for the annotation disappeared.
When I intentionally tried to break it, I couldn't get the behavior you do. The only thing that happened was the modal for the annotation disappeared.
Sep 20, 2021, 11:20 PM
I was able to clone your repo, but the annotation is behaving as it should be. One issue you might be running into is that it turns out that
When I intentionally tried to break it, I coul
When I intentionally tried to break it, I coul
Sep 20, 2021, 11:20 PM
Can you share the JSON of the document that this is happening in? Click the kebab menu at the top right and select Inspect to get it.
Sep 20, 2021, 11:21 PM
E
I thought "email" might be a reserved keyword, so I tried using a couple other random words, but everything except "span" breaks the functionality for me. I'll paste the JSON below... The text i'm highlighting to turn into an email link is at bio[3].children[1].marks.text and the email link itself is at bio[3].markDefs[0].href.
Sep 21, 2021, 3:37 PM
E
bio:[] 6 items 0:{} 5 items _key:074b1d0fcbef _type:block children:[] 1 item 0:{} 4 items _key:5f8de82acdf80 _type:span marks:[] 0 items text:Hey! About me... I'm a freelance web developer, always in search of new projects. I also like to play guitar and write songs, I love to travel, and I have what some people might say is pretty pretentious taste in movies... but the web development part is probably the reason you're here. markDefs:[] 0 items style:normal 1:{} 5 items _key:3a062be61f3f _type:block children:[] 5 items 0:{} 4 items _key:5d2330099df6 _type:span marks:[] 0 items text:I first became interested in building websites several years ago after setting up some personal online small businesses with Etsy and Shopify. From there I found some part-time work doing e-commerce admin for brands like 1:{} 4 items _key:b2708a963bd8 _type:span marks:[] 1 item 0:db986ca35dfe text:JED 2:{} 4 items _key:b8c334b1fd1d _type:span marks:[] 0 items text: and 3:{} 4 items _key:6e7c1ffb4d07 _type:span marks:[] 1 item 0:3f80f5ff5b54 text:Eric Weiner 4:{} 4 items _key:22cdeb0378a8 _type:span marks:[] 0 items text:. This exposed me to the Sanity content manager and got me interested in learning a bit about coding. So I dove in and taught myself HTML, CSS, and JavaScript, and from there I moved on to React, Gatsby, Sanity, ES6, Sass, TypeScript... I learned how to use the terminal and git/github, code editors, how to build sites from scratch and ultimately how to deploy and host them on custom URLs with Netlify. These days I'm interested in continuing to learn new languages and frameworks such as Solidity (for developing on the Ethereum blockchain) and Next.js, to name a couple. markDefs:[] 2 items 0:{} 4 items _key:db986ca35dfe _type:link blank:true href:<https://jedofficial.com/> 1:{} 4 items _key:3f80f5ff5b54 _type:link blank:true href:<https://ericaweiner.com/> style:normal 2:{} 5 items _key:85819524274d _type:block children:[] 1 item 0:{} 4 items _key:07f9284f61e8 _type:span marks:[] 0 items text:I also have experience with - and am fully proficient at - writing and editing copy, editing and resizing images with Photoshop, and collaborating with teams on new product launches. markDefs:[] 0 items style:normal 3:{} 5 items _key:26a1c7da2a3c _type:block children:[] 3 items 0:{} 4 items _key:7951d434123e _type:span marks:[] 0 items text:This website is meant to serve as my portfolio, so poke around and check out some of the work I've done, which includes this site itself. If you're interested in learning more or discussing plans for your next site, or if you think I might make a good addition to your development team, please 1:{} 4 items _key:28849ad817f1 _type:span marks:[] 1 item 0:8f9af4f131c2 text:get in touch 2:{} 4 items _key:2a55da22f51f _type:span marks:[] 0 items text:! I'm currently based in the NYC area but am available for remote work anytime, any place. markDefs:[] 1 item 0:{} 3 items _key:8f9af4f131c2 _type:span href:eric@ericrodgers.io style:normal 4:{} 5 items _key:45f454ee5735 _type:block children:[] 1 item 0:{} 4 items _key:fceef7bd35a1 _type:span marks:[] 0 items text:Thanks for stopping by! markDefs:[] 0 items style:normal 5:{} 5 items _key:2851d159c907 _type:block children:[] 1 item 0:{} 4 items _key:aee8777edf37 _type:span marks:[] 0 items text:Eric markDefs:[] 0 items style:normal image:{} 2 items _type:figure alt:blank name:Me slug:{} 2 items _type:slug current:me
Sep 21, 2021, 3:37 PM
E
oof sorry, i didn't realize it would lose the indentation formatting.... I thought putting it in a code block would retain that...
Sep 21, 2021, 3:38 PM
E
Here's a screen capture of the specific block of JSON under bio[3] showing the span text "get in touch" and the span link "eric@ericrodgers.io "
Sep 21, 2021, 3:42 PM
OK! What's likely happening is that the object was named 'span' when it was first created, so the
You'll need to change the
_typeof that bit of email text is set to
spanin your document's data. If you change the name of the object to 'contact', that piece of data can no longer be interacted with by the same schema that originally defined it because the Studio is looking for an entirely different
_type.
You'll need to change the
_typeon that piece of data in order for it to work with a new name. You can either mutate it using the API (which is probably too complex of a task for just 1 mutation) or you can change the object's name in your schema > save to hot reload the Studio > remove the text that's tied to the old object's name > reenter the text > re-add the email annotation.
Sep 21, 2021, 6:15 PM
E
Hm... I'm not sure I understand how your suggestion is any different to what I've been trying: changing the name of the object to "contact" (or "whatever") in my schema and then saving (which hot reloads the Studio), then updating my serializer to match, then attempting to add the contact link to any text at all. That's what I've been doing, and it still won't work for me unless the object's name in the schema is "span." ☹️ And when I created the object from scratch the first time it was named "email". BUT after my most recent save I ran
npm run graphql-deployto make sure my schema changes were updated in my graphql playground, and in graphql I can see that everything - the normal text, my external url links, and my email contact link - are all
"_type": "span". Not sure if that offers any clues... ANYWAY... I'm just happy it works as is for now... if you are getting it to work off my cloned repo then I'm guessing I'm just misunderstanding something here on my end cuz I'm a newb! Thanks so much for your help Racheal!
Sep 21, 2021, 6:52 PM
I think the important difference is that you need to remove the text then re-add it and the annotation after you change the name of the schema, otherwise those changes will not be reflected in your actual content. But if it works and you're happy with it as is, that's all that matters!
Sep 21, 2021, 6:56 PM
Sanity– build remarkable experiences at scale
Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.