> ## Documentation Index
> Fetch the complete documentation index at: https://docs.contentwrap.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Understanding Portable Text

> Learn about Sanity's Portable Text format and how MigrateKit converts HTML to structured, platform-agnostic content.

## What is Portable Text?

Portable Text is Sanity's rich text format—a structured, JSON-based way to represent content that's more powerful and flexible than HTML.

Unlike HTML (which mixes content and presentation), Portable Text separates **what** the content is from **how** it looks. This makes your content:

* **Platform-agnostic** - Render on web, mobile, email, or anywhere
* **Structured** - Query and filter content programmatically
* **Customizable** - Style differently across platforms
* **Future-proof** - Not tied to specific HTML/CSS

## Portable Text Structure

Portable Text is an array of blocks and marks:

```json theme={null}
[
  {
    "_type": "block",
    "style": "h2",
    "children": [
      {
        "_type": "span",
        "text": "Welcome to Sanity",
        "marks": []
      }
    ]
  },
  {
    "_type": "block",
    "style": "normal",
    "children": [
      {
        "_type": "span",
        "text": "This is a ",
        "marks": []
      },
      {
        "_type": "span",
        "text": "paragraph",
        "marks": ["strong"]
      },
      {
        "_type": "span",
        "text": " with formatting.",
        "marks": []
      }
    ]
  }
]
```

This represents:

```html theme={null}
<h2>Welcome to Sanity</h2>
<p>This is a <strong>paragraph</strong> with formatting.</p>
```

## Key Concepts

### Blocks

**Blocks** are the main content units:

* **Paragraphs** - `style: "normal"`
* **Headings** - `style: "h1"` through `style: "h6"`
* **Lists** - `listItem: "bullet"` or `listItem: "number"`
* **Custom blocks** - Images, code, embeds, etc.

### Marks

**Marks** are inline annotations:

* `strong` - Bold text
* `em` - Italic text
* `underline` - Underlined text
* `code` - Inline code
* `link` - Hyperlinks with `href`

### Spans

**Spans** are text segments within blocks, each with its own marks.

## How MigrateKit Converts HTML

When you migrate from Webflow, MigrateKit transforms HTML to Portable Text:

<Tabs>
  <Tab title="HTML Input">
    ```html theme={null}
    <h2>My Blog Post</h2>
    <p>This is <strong>important</strong> text with a <a href="/link">link</a>.</p>
    <ul>
      <li>First item</li>
      <li>Second item</li>
    </ul>
    ```
  </Tab>

  <Tab title="Portable Text Output">
    ```json theme={null}
    [
      {
        "_type": "block",
        "style": "h2",
        "children": [{"_type": "span", "text": "My Blog Post"}]
      },
      {
        "_type": "block",
        "style": "normal",
        "children": [
          {"_type": "span", "text": "This is "},
          {"_type": "span", "text": "important", "marks": ["strong"]},
          {"_type": "span", "text": " text with a "},
          {"_type": "span", "text": "link", "marks": [{"_type": "link", "href": "/link"}]},
          {"_type": "span", "text": "."}
        ]
      },
      {
        "_type": "block",
        "style": "normal",
        "listItem": "bullet",
        "children": [{"_type": "span", "text": "First item"}]
      },
      {
        "_type": "block",
        "style": "normal",
        "listItem": "bullet",
        "children": [{"_type": "span", "text": "Second item"}]
      }
    ]
    ```
  </Tab>
</Tabs>

Learn more: [HTML Conversion](/concepts/html-conversion)

## Benefits for Migration

### Preservation of Structure

HTML tags become semantic blocks:

| HTML       | Portable Text        | Benefit                          |
| ---------- | -------------------- | -------------------------------- |
| `<h2>`     | `style: "h2"`        | Heading semantics preserved      |
| `<strong>` | `marks: ["strong"]`  | Emphasis meaning, not just bold  |
| `<ul><li>` | `listItem: "bullet"` | List structure, not just bullets |

### Platform Flexibility

Render Portable Text differently on different platforms:

```tsx theme={null}
// Web - styled as H1
<h1 className="text-4xl">{heading}</h1>

// Mobile - styled as H2 for smaller screens
<h2 className="text-2xl">{heading}</h2>

// Email - inline styles
<h2 style="font-size: 24px">{heading}</h2>
```

All from the same Portable Text source!

### Querying and Filtering

Find content programmatically:

```groq theme={null}
// Find all documents with links to /pricing
*[_type == "post" && pt::text(body) match "*pricing*"]
```

You can't do this easily with HTML.

## Editing Portable Text

In Sanity Studio, Portable Text appears as a rich text editor:

Editors see familiar formatting options:

* Bold, italic, underline buttons
* Heading dropdown
* List buttons
* Link insertion
* Undo/redo

But behind the scenes, it's all stored as structured Portable Text.

## Custom Block Types

Portable Text isn't limited to text—you can embed custom content:

```json theme={null}
[
  {
    "_type": "block",
    "children": [{"_type": "span", "text": "Check out this image:"}]
  },
  {
    "_type": "image",
    "asset": {"_ref": "image-abc123-jpg"}
  },
  {
    "_type": "callout",
    "tone": "warning",
    "text": "Important notice!"
  }
]
```

This allows rich, interactive content while keeping structure.

## Why This Matters for Webflow Migrations

### From HTML Chaos to Structured Content

Webflow stores rich text as HTML—a mix of content, structure, and styling. Portable Text separates these concerns:

| Aspect          | HTML (Webflow)            | Portable Text (Sanity)          |
| --------------- | ------------------------- | ------------------------------- |
| **Content**     | Mixed with tags           | Pure text in `children`         |
| **Structure**   | Implicit in tags          | Explicit in `_type` and `style` |
| **Formatting**  | CSS classes/inline styles | Semantic marks                  |
| **Portability** | Web-specific              | Platform-agnostic               |

### Better Content Management

* **Cleaner** - No HTML tag soup
* **Safer** - No script injection risks
* **Flexible** - Render anywhere, any way
* **Searchable** - Query content semantically

## Common Questions

<AccordionGroup>
  <Accordion title="Can I still use HTML?">
    Yes! Sanity supports HTML in Portable Text through custom serializers. But you lose some benefits:

    * Can't query HTML content semantically
    * Platform-specific rendering is harder
    * Less structured

    MigrateKit converts HTML to Portable Text to give you maximum flexibility.
  </Accordion>

  <Accordion title="What if my HTML doesn't convert perfectly?">
    MigrateKit handles most common HTML tags, but complex structures may need manual cleanup:

    * Custom Webflow elements → Code blocks (review in Studio)
    * Nested formatting → Simplified to Portable Text rules
    * Unsupported tags → Wrapped for safety

    See [HTML Conversion](/concepts/html-conversion) for details.
  </Accordion>

  <Accordion title="Can I edit Portable Text as HTML?">
    In Sanity Studio, you edit using the rich text editor (WYSIWYG). To see the raw Portable Text JSON, use Sanity's Vision plugin.

    You typically don't need to edit Portable Text as JSON—the editor handles it.
  </Accordion>

  <Accordion title="Is Portable Text a Sanity-specific format?">
    Portable Text is an **open specification** created by Sanity. While Sanity uses it extensively, you can use Portable Text in any system. It's just JSON!
  </Accordion>
</AccordionGroup>
