Content

Pass markdown, HTML, or JSON content to the Document component.

Overview

The Document component accepts content in three formats: Markdown (default), HTML, or TipTap JSON. Markdown is the default as it's the most common and readable format.

// Markdown (default)
<Document content="# Hello World\n\nThis is **bold** text.">
  <Document.Viewer />
</Document>

// HTML
<Document content="<h1>Hello World</h1><p>This is <strong>bold</strong> text.</p>" contentType="html">
  <Document.Viewer />
</Document>

// JSON (TipTap's native format)
<Document content={jsonContent} contentType="json">
  <Document.Viewer />
</Document>

Markdown (Default)

Pass a markdown string directly. The component uses TipTap's official Markdown extension (powered by MarkedJS) to parse and render the content.

const markdown = `
# Analysis Report

This document contains **important findings** from our investigation.

## Key Points

- First observation with *emphasis*
- Second point with \`inline code\`
- Third point linking to [documentation](https://example.com)

> This is a blockquote highlighting a key statement.

### Code Example

\`\`\`typescript
function analyzeData(input: string): Result {
  return process(input);
}
\`\`\`

| Column A | Column B | Column C |
|----------|----------|----------|
| Data 1   | Data 2   | Data 3   |
| Data 4   | Data 5   | Data 6   |
`;

<Document content={markdown}>
  <Document.Viewer />
</Document>;

Supported Markdown Features

All standard Markdown syntax is supported:

FeatureSyntax
Headings# H1 through ###### H6
Bold**text** or __text__
Italic*text* or _text_
Strikethrough~~text~~
Inline code`code`
Links[text](url)
Images![alt](url)
Blockquotes> quote
Bullet lists- item or * item
Numbered lists1. item
Task lists- [ ] task or - [x] done
Code blocks``` fenced blocks
TablesGFM table syntax
Horizontal rules--- or ***

HTML

For HTML content, set contentType="html":

const htmlContent = `
<h1>Document Title</h1>
<p>Paragraph with <strong>bold</strong> and <em>italic</em> text.</p>
<ul>
  <li>List item one</li>
  <li>List item two</li>
</ul>
`;

<Document content={htmlContent} contentType="html">
  <Document.Viewer />
</Document>;

JSON (TipTap Format)

For programmatic content generation or when you need precise control, use TipTap's JSON format with contentType="json":

const jsonContent = {
  type: "doc",
  content: [
    {
      type: "heading",
      attrs: { level: 1 },
      content: [{ type: "text", text: "My Document" }],
    },
    {
      type: "paragraph",
      content: [
        { type: "text", text: "Regular text " },
        { type: "text", text: "bold text", marks: [{ type: "bold" }] },
      ],
    },
  ],
};

<Document content={jsonContent} contentType="json">
  <Document.Viewer />
</Document>;

Node Types

TypeHTMLNotes
doc-Root node (required)
text-Leaf node, can have marks
paragraph<p>Basic text block
heading<h1>-<h6>attrs: { level: 1-6 }
bulletList<ul>Unordered list
orderedList<ol>Numbered list
listItem<li>List item
blockquote<blockquote>Quote block
codeBlock<pre><code>Code block
horizontalRule<hr>Divider
hardBreak<br>Line break
table<table>Table container
tableRow<tr>Table row
tableHeader<th>Header cell
tableCell<td>Data cell
taskList<ul>Task list container
taskItem<li>Checkbox item

Marks

Inline formatting applied to text nodes:

{
  type: "text",
  text: "formatted text",
  marks: [
    { type: "bold" },
    { type: "italic" },
    { type: "strike" },
    { type: "code" },
    { type: "link", attrs: { href: "https://example.com" } },
  ]
}

Converting Between Formats

If you need to transform content between formats, you can access the TipTap editor instance:

import { useDocument } from "@tilt-legal/cubitt-components/document";

function MyComponent() {
  const { editor } = useDocument();

  // Get content as different formats
  const json = editor?.getJSON();
  const html = editor?.getHTML();
  const markdown = editor?.getMarkdown(); // Requires markdown extension

  return null;
}

Styling

Document.Viewer owns the default rich-text styling for headings, lists, code, blockquotes, tables, task lists, separators, and annotation marks. Inline surfaces, block surfaces, and borders are derived from the current surface context, so embedded document content remains aligned when the viewer is placed inside another Cubitt surface.

Use className on Document.Viewer for layout concerns such as width or scroll containment. Component-level typography and annotation mark colors are part of the Document system.

Annotation Marks

Annotations render as semantic warning marks. Active marks receive stronger warning emphasis when their matching annotation card is selected.

SelectorDescription
mark[data-annotation-id]All annotation marks
mark[data-annotation-id][data-active]Active annotation

On this page