easy-prismic-react
v1.1.0easy-prismic-react
A better way of using Primsic with react. This package doubles as an HTML serializer and an API wrapper. Modern, tested and fully written in typescript.
Based on prismic-reactjs and written here at easyblue.io, a french insurtech company. Check out our website to see how we're using prismic and this package in production.
Installation
yarn install easy-prismic-react
or npm install easy-prismic-react
Basic Usage
HTML Serializer
import { PrismicHTMLSerializer, PrismicDocument } from 'easy-prismic-react';
export function linkResolver(doc: PrismicDocument<any>): string {
switch (doc.type) {
case 'some_content_type':
return `/your/route/${doc.uid}`;
default:
return '/';
}
}
const easyPrismicReact = new PrismicHTMLSerializer({ linkResolver });
function MyComponent () {
return easyPrismicReact.renderRichText(this.props.someRichText);
}
API Wrapper
import { PrismicAPIWrapper, PrismicDocument, PrismicElement } from 'easy-prismic-react';
// The following type lists your prismic custom types ids.
type TContentTypes = 'blog_post' | 'product_page' | 'faq_page';
// You should use an interface for each custom type, this will allow you to have a better type definition throughout your code.
interface BlogPost {
title: string;
content: PrismicElement[];
}
// Instantiate the API wrapper with your prismic endpoint
const apiWrapper = new PrismicAPIWrapper<TContentTypes>({ endpoint: 'https://your-prismic-repo.cdn.prismic.io/api/v2' });
// Simple function that fetches blog posts by only returning content with the `blog_post` type
// If you're fetching data from the server side, use a req-like object from express or next for instance.
// If you're fetching from the client side, just use null instead.
export async function getBlogPost(reqLikeObject: IncomingMessage): Promise<PrismicDocument<BlogPost>> {
return apiWrapper.getContent<BlogPost>(
reqLikeObject,
apiWrapper.getContentByType('blog_post')
);
}
Custom serializers
Although the serializer takes care of turning your WYSIWYG content into proper HTML, you might need to customize how your content is rendered.
The most common use case is the hyperlink serializer. By default, this package will render a plain <a>
tag. You might want to replace that with your own router like react-router or next's router.
In order to set up your own serializers, you need to pass a object when instantiating PrismicHTMLSerializer
like so :
const apiWrapper = new PrismicAPIWrapper({
endpoint: 'https://your-prismic-repo.cdn.prismic.io/api/v2',
customSerializers: {
'hyperlink': (params: SerializeParams) => {
return (
<MyNavigationComponent />
);
}
}
});
Your function will receive a params
argument with everything you might need in order to tweak your rendering. Take a look at the SerializeParams
interface.
💡 You can override all tags that are handled by the serializer, check the
ElementTypes
enum for the complete list.
The getURL
method
If you need to transform a prismic link (PrismicLink
) object into a string, you can use the getURL(prismicLink: PrismicLink): string
method once your serializer is instantiated.
Full API
class PrismicHTMLSerializer {
public static serializers; // Default serializers you might want to use yourself
constructor(params: SerializerSetupParams);
public renderRichText(richText: PrismicElement[], Component: any = Fragment, componentProps = {}, options: SerializeOptions = {}, context?: any): ReactElement;
public getURL(prismicLink: PrismicLink): string;
}
class PrismicAPIWrapper<TContentTypes> {
constructor(params: WrapperSetupParams);
public async initAPI(req: any): Promise<ResolvedApi>;
public async getContent<T>(req: any, query: string[], queryOptions: QueryOptions = {}): Promise<SearchResponse<T>>;
public getContentByType(type: TContentTypes): string[];
public getContentByUID(page: TContentTypes, uid: string): string[];
// TODO : every stripe API parameter needs to have a dedicated method
}
Advanced usage : custom embeds and the context
param
Prismic is a double edged sword : it's very lightweight and easy to pick up, but it might lack some features if you need to render more complicated content inside the WYSIWYG editor. easy-prismic-react
lets you get started quickly, while also giving you leeway in order to implement advanced features.
For our blog, we wanted to display banners with internal links in the middle of articles. Setting up a banner needs to be easy for contributors whilst letting them customizing their content. Here's how it turned out :
The first step is to customize the <pre>
renderer in order to parse these "shortcodes" of some kind.
const easyPrismicReact = new PrismicHTMLSerializer({
linkResolver,
customSerializers: {
['preformatted']: (params: SerializeParams) => {
const { index, context } = params; // Note how we get the context here
// Some logic here in order to find out which embed is being used (or none at all)...
switch (embed) {
case RELATED_POST_SHORT_CODE:
return (<RelatedPostEmbed key={`embed-${index}`} postContext={context}/>);
// More cases...
default:
// This doesn't look like a short code, use the default serializer that's available as a static method
return PrismicHTMLSerializer.serializers.serializeStandardTag('pre', element, children, index);
}
}
}
});
The second step is to pass a context
when calling the serializer. This will let us pass any data that we will get back in our params
argument, inside the custom serializer.
In our blog post component :
function BLogPost () {
const blogPostContext = {}; // Fetch related posts data here
return (
<div>
{ easyPrismicReact.renderRichText(content, Fragment, {}, {}, blogPostContext) }
</div>
);
}
Thanks to this feature, we can access our related posts data that we fetched earlier, and render a proper link, like so :
const RelatedPostEmbed = ({ postContext }) => {
// Extract the related post data from the context we passed a react prop earlier
const relatedPost = getRelatedPost(postContext);
const { data } = relatedPost;
// Render our custom router component leading to the related post
return (
<YourCustomRouter href={...}>
<PostImage image={data.image.url} />
Related post
<h4>{data?.title}</h4>
</YourCustomRouter>
);
};