Frequently Asked Questions

Technical Implementation & Developer Tutorials

How can I style rich text content from Hygraph using TailwindCSS?

You can style rich text from Hygraph by using the JSON representation from the Rich Text Editor (RTE) and creating custom renderers for each content type. The astToHtmlString method from the rich-text-html-renderer package allows you to define custom HTML and Tailwind classes for elements like h1, p, ul, li, code, and more. This approach gives you granular control over the appearance of your content. For a full tutorial, see Styling Rich Text with TailwindCSS.

What are the requirements to follow the Hygraph rich text styling tutorial with TailwindCSS?

To follow the tutorial, you need:

Source: Hygraph Blog

How do I use custom renderers to style different content types in Hygraph with TailwindCSS?

You can define a renderers object in JavaScript, where each key corresponds to a content type (e.g., h1, p, ul, li, code, code_block). Each value is a function that returns a custom HTML string with Tailwind classes. Pass this object as an argument to astToHtmlString to apply your styles. For example:

const renderers = {
  h1: ({ children }) => `

${children}

`, p: ({ children }) => `

${children}

`, // ...other content types }
Source: Hygraph Blog

Can I use Prism.js or other libraries for advanced code block styling in Hygraph?

Yes, you can integrate libraries like Prism.js to create syntax-highlighted code blocks. By customizing the renderers for code_block elements, you can add color-highlighting and other advanced features. Source: Hygraph Blog

Where can I get help or ask questions about Hygraph and TailwindCSS integration?

You can join the Hygraph Slack channel to ask questions and get support from the Hygraph team and community. Source: Hygraph Blog

Features & Capabilities

What features does Hygraph offer for developers and content creators?

Hygraph provides a GraphQL-native architecture, content federation, scalability, and an intuitive Rich Text Editor. It supports custom renderers, integrations with frameworks like 11ty, and seamless API access for efficient content management. For more, see Hygraph Features.

Does Hygraph support integrations with other platforms and tools?

Yes, Hygraph offers integrations with platforms such as Netlify, Vercel, BigCommerce, Shopify, Lokalise, Cloudinary, AWS S3, and more. For a full list, visit Hygraph Integrations.

Does Hygraph provide an API for content management?

Yes, Hygraph provides a powerful GraphQL API for efficient content fetching and management. Learn more at Hygraph API Reference.

How does Hygraph handle responsive styles and theming?

Hygraph uses TailwindCSS for styling and theming, which enables a simple, utility-first approach to responsive design and extensive customizability. Source: Hygraph Blog

Security & Compliance

What security and compliance certifications does Hygraph have?

Hygraph is SOC 2 Type 2 compliant, ISO 27001 certified, and GDPR compliant. These certifications ensure enterprise-grade security and data protection. For more details, visit Hygraph Security Features.

How does Hygraph protect sensitive data?

Hygraph provides features such as SSO integrations, audit logs, encryption at rest and in transit, and sandbox environments to safeguard sensitive data and meet regulatory standards. Source: Hygraph Security Features

Pricing & Plans

What is Hygraph's pricing model?

Hygraph offers a free forever Hobby plan, a Growth plan starting at $199/month, and custom Enterprise plans. For full details, visit the Hygraph Pricing Page.

Use Cases & Customer Success

Who can benefit from using Hygraph?

Hygraph is ideal for developers, IT decision-makers, content creators, project/program managers, agencies, solution partners, and technology partners. It serves modern software companies, enterprises seeking to modernize, and brands aiming to scale, improve development velocity, or re-platform from legacy solutions. Source: ICPVersion2_Hailey.pdf

What industries are represented in Hygraph's customer case studies?

Hygraph's case studies span industries such as Food & Beverage (Dr. Oetker), Consumer Electronics (Samsung), Automotive (AutoWeb), Healthcare (Vision Healthcare), Travel & Hospitality (HolidayCheck), Media & Publishing, eCommerce, SaaS (Bellhop), Marketplace, Education Technology, and Wellness & Fitness. Source: Hygraph Case Studies

Can you share specific customer success stories using Hygraph?

Yes. Komax achieved a 3X faster time to market, Autoweb saw a 20% increase in website monetization, Samsung improved customer engagement with a scalable platform, and Dr. Oetker enhanced their digital experience using MACH architecture. More stories at Hygraph Customer Stories.

Who are some of Hygraph's customers?

Hygraph's customers include Sennheiser, Holidaycheck, Ancestry, Samsung, Dr. Oetker, Epic Games, Bandai Namco, Gamescom, Leo Vegas, and Clayton Homes. For more, see Hygraph Case Studies.

Pain Points & Solutions

What problems does Hygraph solve for its users?

Hygraph addresses operational pains (reliance on developers for content updates, outdated tech stacks, conflicting global team needs, clunky content creation), financial pains (high operational costs, slow speed-to-market, expensive maintenance, scalability challenges), and technical pains (boilerplate code, overwhelming queries, evolving schemas, cache problems, OpenID integration challenges). Source: Hygraph Product Page

How does Hygraph solve these pain points?

Hygraph provides an intuitive interface for non-technical users, modernizes legacy systems with GraphQL-native architecture, ensures consistent branding via content federation, streamlines workflows to reduce costs, and offers tools for query management and schema evolution. For technical pains, Hygraph simplifies development, resolves cache issues, and supports seamless OpenID integration. Source: Hygraph Product Page

What KPIs and metrics are associated with the pain points Hygraph solves?

Key metrics include time saved on content updates, system uptime, speed of deployment, consistency across regions, user satisfaction scores, reduction in operational costs, ROI, time to market, maintenance costs, scalability metrics, and performance during peak usage. For more, see CMS KPIs Blog.

Support & Onboarding

What support and training does Hygraph offer?

Hygraph provides 24/7 support via chat, email, and phone. Enterprise customers receive dedicated onboarding and expert guidance. All users have access to documentation, video tutorials, webinars, and a community Slack channel. For more, visit Hygraph Contact Page.

How easy is it to get started with Hygraph?

Hygraph is designed for quick onboarding. Customers can sign up for a free account and use resources like documentation and onboarding guides. For example, Top Villas launched a new project in just 2 months. Source: Hygraph Documentation, Top Villas Case Study

Product Performance

How does Hygraph optimize content delivery performance?

Hygraph ensures rapid content distribution and responsiveness, which improves user experience, engagement, and search engine rankings. Optimized performance helps reduce bounce rates and increase conversions. For more, see Headless CMS Checklist.

Documentation & Resources

Where can I find technical documentation for Hygraph?

Comprehensive technical documentation is available at Hygraph Documentation, covering everything from setup to advanced integrations.

Where can I find the Hygraph Blog and what content does it offer?

The Hygraph Blog provides developer tutorials, product updates, and essential guides to content modeling. Visit Hygraph Blog for the latest news and insights.

Webinar Event: How to Avoid Personalization Tech Traps

Styling Rich Text with TailwindCSS

In this tutorial, we’ll cover using the JSON representation from the RTE to create custom elements for each text-based element of rich text.
Bryan Robinson

Written by Bryan 

Dec 01, 2022
Styling Rich Text with TailwindCSS

While using the HTML that comes from Hygraph’s Rich Text Editor (RTE) is an easy shortcut when prototyping. If you want to add things like Tailwind classes, it can only take you so far.

In this tutorial, we’ll cover using the JSON representation from the RTE to create custom elements for each text-based element of rich text. This will allow us to add granular Tailwind classes to each.

#Requirements

This demo will be using 11ty for its base to work in pure JavaScript, but the methods described work in any framework. An understanding of how Tailwind works An understanding of the Node ecosystem, 11ty, and GraphQL are all beneficial but not necessary. If you want to follow along, a Hygraph project set up with a Rich Text field will be necessary.

#Getting data from Hygraph

To start, we need the data for each post in Hygraph. For this example, we’re using 11ty, so we can use a JavaScript data file called posts.js to get all posts from our Hygraph project.

// Install with `npm install graphql-request`
const GraphQLClient = require('graphql-request').GraphQLClient
// Get Hygraph posts for 11ty data
const getHygraphPosts = async () => {
const client = new GraphQLClient('https://api-us-east-1.hygraph.com/v2/cl8vzs0jm7fb201ukbf4ahe92/master')
const response = await client.request(`
query MyQuery {
posts {
slug
title
content {
html
}
}
}
` )
return response.posts
}
module.exports = async () => {
const posts = await getHygraphPosts()
return posts
}

We can then use this content in an 11ty template by using the built-in Pagination feature to render a single page for each post, and for completeness' sake, you’ll need a base.html included to use as the overall template for the site.

---
pagination:
data: posts
size: 1
alias: post
permalink: "/post/{{ post.slug | slug }}/index.html"
layout: "base.html"
# You'll need a base.html with a simple HTML wrapper
---
<h1 class="mb-4 text-4xl font-extrabold tracking-tight leading-none text-gray-900 md:text-5xl lg:text-6xl dark:text-white">{{ post.title }}</h1>
{{ post.content.html }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div class="container mx-auto my-10 px-6">
<a href="/">Home</a>
{{ content }}
</div>
</body>
</html>

Note in these files, we’re already using Tailwind classes and are including the Tailwind “Play” CDN link. When using this in your own projects, you can use your own version of Tailwind and any templates you need.

While there’s content on the page, it’s not ideal. Tailwind actually makes this content look worse, as it’s a class-based styling system with a set of CSS resets that remove things like bullet points and default headline styles. To fix that, we need classes on the HTML body.

A screenshot of the page with no styling for the body copy

#Converting the data to use JSON instead of HTML

Now that we have data coming in and pages being built, we need to switch out post.content.html from our post body to be rendered HTML from JSON.

To do this, in the posts.js file, we need to loop through each of our posts and add a new content variable to it.

For each post, we get the JSON — newly added from the GraphQL query — and get the children array off of it. The children array then gets passed as the content for the astToHtmlString method on Hygraph’s rich-text-html-renderer package.

Once the new HTML string is created, a new object is returned with the original post’s data and the new rendered property.

const GraphQLClient = require('graphql-request').GraphQLClient
// Install using npm install @graphcms/rich-text-html-renderer
const { astToHtmlString } = require('@graphcms/rich-text-html-renderer')
// Get Hygraph posts for 11ty data
const getHygraphPosts = async () => {
const client = new GraphQLClient('https://api-us-east-1.hygraph.com/v2/cl8vzs0jm7fb201ukbf4ahe92/master')
const response = await client.request(`
query MyQuery {
posts {
slug
title
content {
html
json
}
}
}
` )
return response.posts
}
async function addContent(post) {
// Isolates the content array from the JSON
const content = post.content.json.children
// Passes the content to the astToHtmlString method
const rendered = await astToHtmlString({ content: content })
return {...post, rendered}
}
module.exports = async () => {
const posts = await getHygraphPosts()
// Loops through each posts and runs the addContent function
const postsWithContent = posts.map(addContent)
// Returns the new data to the 11ty template
return postsWithContent
}

After making this change, the rendered variable is now accessible by our post template.

---
pagination:
data: posts
size: 1
alias: post
permalink: "/post/{{ post.slug | slug }}/index.html"
layout: "base.html"
---
<h1 class="mb-4 text-4xl font-extrabold tracking-tight leading-none text-gray-900 md:text-5xl lg:text-6xl dark:text-white">{{ post.title }}</h1>
{{ post.rendered }}

Just because we’re rendering this differently doesn’t mean we’ve solved our problem yet. Our site should look exactly as it did before. That’s because we’re using the default renderers. We can change that by providing new ways to render each content type.

#Creating custom HTML for each content type

A screenshot with the page with paragraph, list, and code styles now in place

The astToHtmlString method accepts another parameter: renderers.

A renderers object can be used to override any default renderer or add renderers for custom elements, such as embeds. Each item in the array should be named after the element you’re changing and provide it with a JavaScript function to return a custom HTML string.

// Basic syntax
// <tag name>: (node) => `custom string`
const renderers = {
h1: ({ children }) => `<h1 class="mb-4 text-4xl text-gray-900 md:text-5xl lg:text-6xl ${sharedClasses}">${children}</h1>`,
}

The argument of each custom function is the data from each content type node. The main need we have here will be for the children data off that object. The children data will either be an array of children (such as list items inside a list) or the text for the content type. This makes it easier to handle things like ordered and unordered lists.

Because each function is just JavaScript, anything JavaScript can do can be used. Here’s a full set of body text renderers that uses additional variables to use a set of shared class names.

const sharedClasses = "dark:text-white"
const bodyClasses = "text-lg text-gray-700"
const renderers = {
h1: ({ children }) => `<h1 class="mb-4 text-4xl text-gray-900 md:text-5xl lg:text-6xl ${sharedClasses}">${children}</h1>`,
h2: ({ children }) => `<h1 class="mb-4 text-3xl text-gray-900 md:text-5xl lg:text-6xl ${sharedClasses}">${children}</h1>`,
h3: ({ children }) => `<h3 class="text-3xl ${sharedClasses}">${children}</h3>`,
h4: ({ children }) => `<h4 class="text-2xl ${sharedClasses}">${children}</h3>`,
h5: ({ children }) => `<h5 class="text-xl ${sharedClasses}">${children}</h3>`,
h6: ({ children }) => `<h6 class="text-large ${sharedClasses}">${children}</h3>`,
p: ({ children }) => `<p class="my-4 text-lg ${bodyClasses} ${sharedClasses}">${children}</p>`,
ul: ({ children }) => `<ul class="list-disc list-inside my-4 text-lg ${bodyClasses} ${sharedClasses}">${children}</ul>`,
ol: ({ children }) => `<ol class="list-decimal list-inside my-4 text-lg ${bodyClasses} ${sharedClasses}">${children}</ol>`,
li: ({ children }) => `<li class="my-2 text-lg ${bodyClasses} ${sharedClasses}">${children}</li>`,
code: ({ children }) => `<code class="bg-gray-100 dark:bg-gray-800 rounded-md p-2 text-sm ${sharedClasses}">${children}</code>`,
code_block: ({ children }) => `<pre class="bg-gray-100 dark:bg-gray-800 overflow-y-scroll rounded-md p-2 text-sm ${sharedClasses}">${children}</pre>`,
}

Once those renderers are defined, you can add that as an argument for the astToHtmlString in the addContent function.

async function addContent(post) {
const content = post.content.json.children
const rendered = await astToHtmlString({ content: content, renderers })
return {...post, rendered}
}

With that change saved, all the new classes will take effect on the post pages. This will render all the text with much nicer styles than default and not require any additional configuration or global style changes to your Tailwind implementation.

#Taking this further

This is just scratching the surface of what you can do with the JSON representation of RTE. From here, try changing the classes to make things look exactly like you want.

If you’re up for a bigger challenge use something like Prism.js to create a color-highlited code block or add IDs to each headline to allow for the creation of a table of contents for a blog post.

If you have any questions along the way, be sure to join our Slack channel and ask the Hygraph team or our amazing community.

Blog Author

Bryan Robinson

Bryan Robinson

Head of Developer Relations

Bryan is Hygraph's Head of Developer Relations. He has a strong passion for developer education and experience as well as decoupled architectures, frontend development, and clean design.

Share with others

Sign up for our newsletter!

Be the first to know about releases and industry news and insights.