An opinionated guide to Sanity Studio
Sanity Studio is an incredibly flexible tool with near limitless customisation. Here's how I use it.
Go to An opinionated guide to Sanity StudioGet the best of both worlds. Tailwind-styled typography and Portable Text's markup-and-components structure.
You may no longer need this! The Typography Plugin now supports a not-prose
class which escapes from prose
formatting. Make sure your Portable Text components use this class and you'll no longer need to add the additional step described below.
Tailwind CSS Typography helps you render markup with beautiful styles.
Portable Text combines text markup with Components in one piece of data.
However the .prose
class with its CSS inheritance can mess up any Components sprinkled within markup.
With a clever use of reduce
we can get the best of both worlds. Thanks to Robin Malfait for pointing me in this direction.
This guide has been updated to use the new portabletext/react-portabletext
component! Check out the migration guide if you're updating too.
Use this Component just as you would your normal PortableText Component. For example:
<ProseableText value={value} />
Considerations:
portabletext/react-portabletext
package.prose
classes as a prop so this Component is more reusableprose
will remove the top/bottom margin from the first/last element in an element respectively – you may wish to add this back in. The py-4
class is added in the demo below for this reason.serializers
, add container: ({children}) =>children
so that blocks are not rendered with a wrapping <div>
import React, {useMemo} from 'react'
import {PortableText} from '../lib/sanity'
/**
* Use Tailwind CSS's `prose` classes with Portable Text markup (blocks)
* Without inheriting styles for custom components (types)
*/
export default function ProseableText({value = []}) {
// Group together standard `_type === "block"` blocks
// eg <p>, <li>, etc – and separate out everyone else
const valueGroups = useMemo(
() =>
value.reduce(
(acc, item) => {
const lastIdx = acc.length - 1
if (
// We don't have items in this group yet
acc[lastIdx].length === 0 ||
// The last group has the same `type`
acc[lastIdx][0]._type === item._type
) {
acc[lastIdx].push(item)
} else {
// Time to create a new group, because the `type` is different compared to last group
acc.push([item])
}
return acc
},
[[]]
),
[blocks]
)
if (!valueGroups?.length) return null
return valueGroups.map((group) =>
group[0]._type === 'block' ? (
<div key={group[0]._key} className="prose py-4">
<PortableText value={group} />
</div>
) : (
<PortableText key={group[0]._key} value={group} />
)
)
}
Sanity Composable Content Cloud is the headless CMS that gives you (and your team) a content backend to drive websites and applications with modern tooling. It offers a real-time editing environment for content creators that’s easy to configure but designed to be customized with JavaScript and React when needed. With the hosted document store, you query content freely and easily integrate with any framework or data source to distribute and enrich content.
Sanity scales from weekend projects to enterprise needs and is used by companies like Puma, AT&T, Burger King, Tata, and Figma.
Sanity Studio is an incredibly flexible tool with near limitless customisation. Here's how I use it.
Go to An opinionated guide to Sanity StudioIt can be useful for testing plugins, front ends, or other integrations to have a Sanity Studio populated with fake content.
Go to How to generate massive amounts of demo content for SanitySetup "Live by Default" fetches and interactive live preview with Presentation in Sanity Studio
Go to Visual Editing with Next.js App Router and Sanity StudioSummarise form progression by decorating the entire editing form for a document with a component loaded at the root level.
Go to Create a document form progress component