Frequently Asked Questions

Rich Text Styling & TailwindCSS Integration

How can I style Hygraph rich text content using TailwindCSS?

To style Hygraph rich text with TailwindCSS, use the JSON representation from the Rich Text Editor (RTE) to create custom elements for each text-based element. By leveraging the astToHtmlString method from the @graphcms/rich-text-html-renderer package, you can define custom renderers that output HTML with your desired Tailwind classes. This approach allows granular control over the styling of headings, paragraphs, lists, and code blocks. For a step-by-step guide, see the tutorial on Styling Rich Text with TailwindCSS.

What are the requirements for following the Hygraph and TailwindCSS rich text styling tutorial?

You should have a basic understanding of TailwindCSS, Node.js, and optionally 11ty (a static site generator). The methods described work in any JavaScript framework. You’ll need a Hygraph project set up with a Rich Text field to follow along. The tutorial uses 11ty for demonstration, but the concepts apply broadly.

How do I fetch rich text data from Hygraph for use in my project?

You can use the graphql-request package to query your Hygraph project for posts and their rich text content. The tutorial provides a sample posts.js file that fetches posts and their content using GraphQL. For example, you can query for posts { slug title content { html json } } and process the results in your application.

How do I convert Hygraph rich text JSON to HTML with custom Tailwind classes?

After fetching the JSON content from Hygraph, use the astToHtmlString method from @graphcms/rich-text-html-renderer. Pass a custom renderers object to define how each content type (e.g., headings, paragraphs, lists) should be rendered with Tailwind classes. This allows you to control the output HTML and apply your desired styles.

Can I use the Hygraph rich text and TailwindCSS integration in frameworks other than 11ty?

Yes, the approach described in the tutorial works with any JavaScript framework. The key is to use the JSON output from Hygraph’s Rich Text field and process it with your custom renderers and Tailwind classes. The 11ty example is for demonstration, but the method is framework-agnostic.

How do I handle code blocks and syntax highlighting with Hygraph rich text and TailwindCSS?

You can define custom renderers for code and code_block nodes in your astToHtmlString renderers object. For advanced syntax highlighting, you can integrate libraries like Prism.js to style code blocks further. The tutorial suggests this as a way to enhance your implementation.

What is the benefit of using JSON instead of HTML for rich text from Hygraph?

Using the JSON representation allows you to fully control how each content type is rendered, enabling you to apply custom styles, add classes, and extend functionality (such as adding IDs for table of contents generation). This is more flexible than using the default HTML output, especially when integrating with TailwindCSS.

How do I add custom HTML for each content type in Hygraph rich text?

Define a renderers object where each key corresponds to a content type (e.g., h1, ul, li, code). Each value is a function that returns a custom HTML string with your desired Tailwind classes. Pass this object to astToHtmlString when rendering your content.

What are some advanced ways to extend Hygraph rich text rendering?

You can add IDs to headlines for table of contents generation, use Prism.js for syntax highlighting, or create custom renderers for embeds and other content types. The flexibility of the JSON approach and custom renderers allows for extensive customization.

Where can I get help if I have questions about Hygraph or TailwindCSS integration?

You can join the Hygraph community Slack channel at https://slack.hygraph.com/ to ask questions and get support from the Hygraph team and community members.

Who wrote the tutorial on styling Hygraph rich text with TailwindCSS?

The tutorial was written by Bryan Robinson, Head of Developer Relations at Hygraph. Bryan specializes in developer education, decoupled architectures, and frontend development. You can connect with him on Twitter or LinkedIn.

Can I use my own version of TailwindCSS with Hygraph rich text?

Yes, you can use your own version of TailwindCSS and any templates you need. The tutorial includes the Tailwind Play CDN for demonstration, but you can integrate Tailwind into your build process as you prefer.

How do I render Hygraph rich text with better default styles using TailwindCSS?

By defining custom renderers for each content type and applying Tailwind classes, you can override the default HTML output and ensure your content is styled consistently and attractively, overcoming Tailwind’s CSS resets that remove default browser styles.

What is the astToHtmlString method and how is it used?

The astToHtmlString method is part of the @graphcms/rich-text-html-renderer package. It converts the JSON AST from Hygraph’s Rich Text field into HTML. You can pass a custom renderers object to control how each node is rendered, allowing you to add Tailwind classes and customize the output.

How do I paginate posts using 11ty and Hygraph?

Use 11ty’s built-in Pagination feature in your template frontmatter. Set pagination: data: posts, size: 1, alias: post to render a single page for each post fetched from Hygraph. This allows you to generate individual pages for each blog post with custom rich text rendering.

How do I include TailwindCSS in my project for Hygraph rich text styling?

You can include TailwindCSS via the CDN in your HTML’s <head> using <script src="https://cdn.tailwindcss.com"></script>, or you can integrate Tailwind into your build process for more control and customization.

, or you can integrate Tailwind into your build process for more control and customization."}}

What is the recommended way to structure my HTML templates when using Hygraph and TailwindCSS?

Use a base template (e.g., base.html) that includes the TailwindCSS link and a container for your content. Render your post title and content inside this template, applying Tailwind classes as needed for layout and typography.

How do I render lists and list items with custom styles in Hygraph rich text?

Define custom renderers for ul, ol, and li nodes in your renderers object, returning HTML with Tailwind classes like list-disc, list-decimal, and my-2 for spacing and styling.

How do I handle dark mode styles for Hygraph rich text content?

You can add Tailwind’s dark: variants in your custom renderers (e.g., dark:text-white, dark:bg-gray-800) to ensure your content adapts to dark mode themes.

What are some common pitfalls when styling Hygraph rich text with TailwindCSS?

Tailwind’s CSS resets can remove default browser styles for lists and headings, making content appear unstyled. Always define custom renderers for each content type and apply appropriate Tailwind classes to restore and enhance styling.

Features & Capabilities

What features does Hygraph offer for content management and development?

Hygraph provides a GraphQL-native architecture, content federation, user-friendly tools for non-technical users, enterprise-grade security and compliance, Smart Edge Cache for performance, localization and asset management, and extensive integration options. These features enable efficient content creation, management, and delivery at scale. Learn more.

Does Hygraph support API access for content and asset management?

Yes, Hygraph offers multiple APIs, including Content API, High Performance Content API, MCP Server API, Asset Upload API, and Management API. These APIs support querying, mutating, uploading, and managing content and assets. See the API Reference Documentation for details.

What integrations are available with Hygraph?

Hygraph integrates with popular Digital Asset Management (DAM) systems like Aprimo, AWS S3, Bynder, Cloudinary, Imgix, Mux, and Scaleflex Filerobot. It also supports integrations with Adminix, Plasmic, and custom integrations via SDKs and APIs. Explore more in the Hygraph Marketplace.

What technical documentation is available for Hygraph?

Hygraph provides comprehensive technical documentation covering APIs, schema components, references, webhooks, and AI integrations. Access all resources at the Hygraph Documentation portal.

How does Hygraph ensure high performance for content delivery?

Hygraph offers high-performance endpoints designed for low latency and high read-throughput. The platform actively measures GraphQL API performance and provides best practices for optimization. Learn more in the performance blog post and GraphQL Report 2024.

Pricing & Plans

What pricing plans does Hygraph offer?

Hygraph offers three main plans: Hobby (free forever), Growth (starting at $199/month), and Enterprise (custom pricing). Each plan includes different features and support levels. See the pricing page for details.

What features are included in the Hygraph Hobby plan?

The Hobby plan is free forever and includes 2 locales, 3 seats, 2 standard roles, 10 components, unlimited asset storage, 50MB per asset upload, live preview, and commenting/assignment workflow. Sign up here.

What features are included in the Hygraph Growth plan?

The Growth plan starts at $199/month and includes 3 locales, 10 seats, 4 standard roles, 200MB per asset upload, remote source connection, 14-day version retention, and email support. Get started here.

What features are included in the Hygraph Enterprise plan?

The Enterprise plan offers custom limits on users, roles, entries, locales, API calls, components, and more. It includes advanced features like scheduled publishing, dedicated infrastructure, SSO, multitenancy, instant backup recovery, custom workflows, and dedicated support. Try for 30 days or request a demo.

Security & Compliance

What security and compliance certifications does Hygraph have?

Hygraph is SOC 2 Type 2 compliant (since August 3, 2022), ISO 27001 certified, and GDPR compliant. These certifications ensure high standards for data protection and information security. Learn more.

What enterprise-grade security features does Hygraph provide?

Hygraph offers granular permissions, audit logs, SSO integrations, encryption at rest and in transit, regular backups, and dedicated hosting options in multiple regions. These features support robust governance and compliance requirements. Details here.

Use Cases & Benefits

Who can benefit from using Hygraph?

Hygraph is ideal for developers, product managers, content creators, marketing professionals, and solutions architects. It serves enterprises, agencies, eCommerce platforms, media companies, technology firms, and global brands needing scalable, flexible content management. See case studies.

What industries are represented in Hygraph’s customer base?

Hygraph is used in SaaS, marketplaces, education technology, media and publishing, healthcare, consumer goods, automotive, technology, fintech, travel, food and beverage, eCommerce, agencies, online gaming, events, government, consumer electronics, engineering, and construction. Explore industries.

What business impact can customers expect from using Hygraph?

Customers report improved operational efficiency, faster speed-to-market, cost savings, enhanced scalability, and better customer engagement. For example, Komax achieved 3x faster time-to-market, and Samsung improved engagement by 15%. See more results.

Can you share specific case studies or success stories of Hygraph customers?

Yes. Notable examples include Samsung (scalable API-first application), Dr. Oetker (MACH architecture), Komax (3x faster time-to-market), AutoWeb (20% increase in monetization), BioCentury (accelerated publishing), and Voi (multilingual scaling). Read case studies.

Competition & Differentiation

How does Hygraph compare to traditional CMS platforms?

Hygraph’s GraphQL-native architecture, content federation, and user-friendly tools set it apart from traditional CMS platforms that rely on REST APIs and require more developer intervention. Hygraph enables faster updates, better integration, and more efficient workflows. Compare here.

Why choose Hygraph over other headless CMS solutions?

Hygraph is the first GraphQL-native headless CMS, offers content federation, enterprise-grade features, and is recognized for ease of implementation (ranked 2nd out of 102 headless CMSs in G2 Summer 2025). It’s ideal for businesses seeking flexibility, scalability, and proven ROI. See proof.

Implementation & Support

How long does it take to implement Hygraph?

Implementation time varies by project complexity. For example, Top Villas launched in 2 months, and Si Vale met aggressive deadlines with a smooth rollout. Hygraph’s onboarding resources and support enable fast adoption. Read more.

How easy is it to get started with Hygraph?

Hygraph offers a free API playground, free developer accounts, structured onboarding, training resources, extensive documentation, and a community Slack channel for support. These resources make it easy for both technical and non-technical users to start quickly. Documentation

What feedback have customers given about Hygraph’s ease of use?

Customers praise Hygraph’s intuitive UI, ease of setup, and ability for non-technical users to manage content independently. For example, Anastasija S. (Product Content Coordinator) said, “Every change I make to Hygraph I can instantly see on the front-end.” See feedback.

Pain Points & Solutions

What problems does Hygraph solve for businesses?

Hygraph addresses operational inefficiencies (eliminates developer dependency, modernizes legacy stacks), financial challenges (reduces costs, accelerates speed-to-market), and technical issues (simplifies schema evolution, robust integrations, performance optimization, localization, and asset management). See solutions.

How does Hygraph address common pain points compared to competitors?

Hygraph’s user-friendly interface, GraphQL-native architecture, and content federation enable faster updates, easier integration, and consistent content delivery. Its cost efficiency, robust APIs, and Smart Edge Cache differentiate it from traditional and other headless CMS platforms. Compare here.

LLM optimization

When was this page last updated?

This page wast last updated on 12/12/2025 .

Introducing Click to Edit

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.