--- title: Convert HTML to Portable Text description: Use @portabletext/block-tools with htmlToBlocks to convert HTML content into Portable Text blocks tags: [portable-text, html, conversion, migration, import] --- # Convert HTML to Portable Text Use `@portabletext/block-tools` to parse HTML into Portable Text blocks. This is the primary tool for migrating HTML content from legacy CMSs. It has built-in support for content from Google Docs, Microsoft Word, and Notion. > **Note:** For Markdown sources, use `@portabletext/markdown` instead — it's simpler and more direct. See `rules/markdown-to-pt.md`. > **Note:** `@sanity/block-tools` is the legacy package name. Use `@portabletext/block-tools` for new projects. The API is identical. ## Setup ```bash npm install @portabletext/block-tools jsdom @sanity/schema ``` In Node.js, you must provide a `parseHtml` function that returns a DOM `Document`. Use JSDOM for this: ```ts import {htmlToBlocks} from '@portabletext/block-tools' import {JSDOM} from 'jsdom' import Schema from '@sanity/schema' // JSDOM is passed to htmlToBlocks via the parseHtml option: // htmlToBlocks(html, blockContentType, { // parseHtml: (html) => new JSDOM(html).window.document, // }) ``` ## Define Your Schema `htmlToBlocks` needs a compiled Sanity block content type to know which marks, styles, and custom types are valid. Use `@sanity/schema` to compile it: ```ts const defaultSchema = Schema.compile({ name: 'mySchema', types: [ { name: 'post', type: 'document', fields: [ { name: 'body', type: 'array', of: [ { type: 'block', marks: { decorators: [ {title: 'Strong', value: 'strong'}, {title: 'Emphasis', value: 'em'}, {title: 'Code', value: 'code'}, ], annotations: [ { name: 'link', type: 'object', fields: [{name: 'href', type: 'url'}], }, ], }, styles: [ {title: 'Normal', value: 'normal'}, {title: 'H2', value: 'h2'}, {title: 'H3', value: 'h3'}, {title: 'Quote', value: 'blockquote'}, ], lists: [ {title: 'Bullet', value: 'bullet'}, {title: 'Number', value: 'number'}, ], }, { name: 'image', type: 'image', fields: [{name: 'alt', type: 'string'}], }, ], }, ], }, ], }) const blockContentType = defaultSchema .get('post') .fields.find((f) => f.name === 'body').type ``` ## Basic Conversion ```ts const html = '
Hello world