Being able to download blocks as a PDF?
Great question! Generating PDFs from Portable Text blocks is definitely doable, and several people in the community have tackled this. Here's how you can approach it:
The General Approach
The key is to use Portable Text serializers to transform your blocks into an intermediate format that a PDF library can work with. You have a few options:
1. Using Sanity Functions (Recommended)
The modern approach is to use Sanity Functions - serverless functions that can process your content. You could create a function that:
- Receives a document ID or specific blocks
- Serializes the Portable Text to HTML
- Uses a PDF generation library like
puppeteer,playwright, or@react-pdf/renderer - Returns the PDF file or uploads it to your storage
This keeps everything within the Sanity ecosystem and scales automatically without needing external hosting.
2. Server-Side Generation
If you're running your own backend, you can create an API endpoint that:
- Queries the content from Sanity using GROQ
- Serializes Portable Text to HTML using
@portabletext/to-htmlor custom serializers - Converts HTML to PDF using libraries like:
- pdfmake (works with JSON structure)
- puppeteer or playwright (renders HTML to PDF)
- jsPDF with html2canvas
- @react-pdf/renderer (if you want React-based PDF layouts)
3. Example Workflow
// Serialize Portable Text to HTML
import { toHTML } from '@portabletext/to-html'
const html = toHTML(blocks, {
components: {
types: {
image: ({value}) => `<img src="${value.asset.url}" />`,
// Add custom handlers for your block types
}
}
})
// Then use puppeteer or similar
import puppeteer from 'puppeteer'
const browser = await puppeteer.launch()
const page = await browser.newPage()
await page.setContent(html)
const pdf = await page.pdf({ format: 'A4' })Considerations
- Styling: Make sure your serializers include proper CSS for the PDF layout
- Images: Handle image URLs properly (they need to be accessible to the PDF generator)
- Custom blocks: You'll need serializers for any custom block types you have
- Performance: PDF generation can be resource-intensive, so consider caching or background processing
The ultimate guide for customizing Portable Text has great examples of custom serializers that would be helpful here.
Would love to hear what approach you end up taking! If you share more about your block structure, the community might have more specific suggestions.
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.