Complete Guide to AFFiNE Block Types: Every Built-in Block Explained
AFFiNE's editor supports over 20 built-in block types identified by flavour strings prefixed with affine:, ranging from basic paragraphs and lists to complex embeds, databases, and whiteboard surfaces.
AFFiNE block types form the foundation of the editor's content architecture, built on the open-source BlockSuite framework maintained in the toeverything/AFFiNE repository. Every piece of content—from simple text to embedded Figma designs—is stored as a typed block with a unique flavour identifier. Understanding these block types is essential for developers extending AFFiNE or automating document creation via the BlockSuite API.
Understanding AFFiNE's Block Architecture
The Flavour System
Blocks in AFFiNE are identified by a flavour string prefixed with affine:. This system allows the editor to distinguish between different content types and apply appropriate rendering, serialization, and interaction logic. The flavour serves as the primary key when creating blocks programmatically via doc.addBlock(flavour, props, parentId).
Block Hierarchy and Nesting
AFFiNE documents follow a strict hierarchical structure defined in blocksuite/affine/shared/src/types/index.ts:
affine:pageserves as the root container for every documentaffine:noteacts as the primary content container within pages- Content blocks (paragraphs, lists, images) nest inside notes
- Edgeless mode uses
affine:surfaceas the canvas root
Complete Catalogue of AFFiNE Block Types
Container Blocks
These blocks provide structural organization for documents:
-
affine:page— The top-level page container. Every AFFiNE document starts with this block as its root. Referenced intests/blocksuite/e2e/zero-width.spec.ts(line 46). -
affine:note— Generic container for free-form content; the most common parent for text and media blocks. Found intests/blocksuite/e2e/zero-width.spec.ts(line 49).
Content Blocks
Fundamental text and media blocks for document creation:
-
affine:paragraph— Rich-text paragraph supporting headings, lists, and inline formatting. Implementation tested intests/blocksuite/e2e/paragraph.spec.ts(line 245). -
affine:list— List block supporting bulleted, numbered, and todo list styles. Created viadoc.addBlock('affine:list', { type: 'bulleted' }, parentId)as shown intests/blocksuite/e2e/list.spec.ts(line 64). -
affine:code— Code block with syntax highlighting, language selector, and copy functionality. Defined intests/blocksuite/e2e/code/crud.spec.ts(line 42). -
affine:divider— Horizontal rule for visual section separation. Referenced intests/blocksuite/e2e/zero-width.spec.ts(line 78). -
affine:image— Inline image supporting local file upload or remote URL. Found intests/blocksuite/e2e/zero-width.spec.ts(line 88). -
affine:bookmark— URL bookmark block that fetches preview thumbnails. Located intests/blocksuite/e2e/zero-width.spec.ts(line 79).
Embed Blocks
Specialized blocks for embedding external content and linked documents:
-
affine:embed-github— Embedded GitHub gist or file viewer. Referenced intests/blocksuite/e2e/zero-width.spec.ts(line 89). -
affine:embed-figma— Figma design embed. Defined inblocksuite/affine/widgets/keyboard-toolbar/src/config.ts(line 1005). -
affine:embed-youtube— YouTube video embed. Configured inblocksuite/affine/widgets/keyboard-toolbar/src/config.ts(line 1015). -
affine:embed-iframe— Generic iframe embed for external web pages. Found inblocksuite/affine/widgets/keyboard-toolbar/src/config.ts(line 1050). -
affine:embed-linked-doc— Inline view of another AFFiNE page (linked document). Defined inblocksuite/affine/widgets/keyboard-toolbar/src/config.ts(line 1073). -
affine:embed-synced-doc— Embedded synced document that stays synchronized with its source. Located inblocksuite/affine/widgets/keyboard-toolbar/src/config.ts(line 1115).
Edgeless and Canvas Blocks
Blocks specific to whiteboard and Edgeless mode:
-
affine:surface— Whiteboard/canvas block used in Edgeless mode. Created intests/blocksuite/e2e/edgeless/edgeless-text.spec.ts(line 616). -
affine:surface-ref— Reference to a surface used internally for linking Edgeless canvases. Defined inblocksuite/affine/blocks/surface/src/view.ts(line 22).
Database Blocks
Structured data blocks:
-
affine:database— Full-featured database table/list block with views. Referenced intests/blocksuite/e2e/zero-width.spec.ts(line 341). -
affine:todo— Technically a variant ofaffine:listwith the "todo" style, representing checklist items. Found intests/blocksuite/e2e/list.spec.ts(line 80).
Programmatic Block Creation with BlockSuite
Developers can instantiate any AFFiNE block type via the BlockSuite API using doc.addBlock(). This method accepts the flavour string, properties object, and parent block ID.
Creating Container Structures
Every AFFiNE document requires a hierarchical structure starting with affine:page:
// Create the root page container
const pageId = doc.addBlock('affine:page', {}, null);
// Add a note container for content
const noteId = doc.addBlock('affine:note', {}, pageId);
Source: tests/blocksuite/e2e/zero-width.spec.ts (lines 46, 49)
Adding Text Content
Insert rich-text paragraphs with initial content:
const paragraphId = doc.addBlock(
'affine:paragraph',
{ text: 'Hello AFFiNE!' },
noteId
);
Source: tests/blocksuite/e2e/paragraph.spec.ts (line 245)
Inserting Code Blocks
Create syntax-highlighted code blocks with language specification:
const codeProps = {
language: 'typescript',
// initial empty text will be replaced by the editor UI
};
doc.addBlock('affine:code', codeProps, noteId);
Source: tests/blocksuite/e2e/code/crud.spec.ts (line 42)
Creating Lists
Instantiate various list styles using the type property:
// Bulleted list
doc.addBlock('affine:list', { type: 'bulleted' }, noteId);
// Numbered list
doc.addBlock('affine:list', { type: 'numbered' }, noteId);
// Todo/checklist
doc.addBlock('affine:list', { type: 'todo' }, noteId);
Source: tests/blocksuite/e2e/list.spec.ts (lines 64, 80)
Embedding External Content
Insert external resources and linked documents:
// GitHub embed
doc.addBlock('affine:embed-github', { url: 'https://gist.github.com/...' }, noteId);
// YouTube video
doc.addBlock('affine:embed-youtube', { url: 'https://youtu.be/...' }, noteId);
// Linked AFFiNE page
doc.addBlock('affine:embed-linked-doc', { pageId: 'some-page-id' }, noteId);
// Synced document (stays updated with source)
doc.addBlock('affine:embed-synced-doc', { pageId: 'source-page-id' }, noteId);
Source: blocksuite/affine/widgets/keyboard-toolbar/src/config.ts (lines 1005, 1015, 1073, 1115)
Adding Whiteboard Surfaces
Create Edgeless mode canvas blocks:
// Surface block for whiteboard/Edgeless mode
const surfaceId = doc.addBlock('affine:surface', {}, pageId);
Source: tests/blocksuite/e2e/edgeless/edgeless-text.spec.ts (line 616)
Key Implementation Files
The block type system is implemented across these critical source files:
-
blocksuite/affine/shared/src/types/index.ts— Defines the central TypeScript unionBlockFlavourthat enumerates all valid block type strings. -
packages/frontend/core/src/blocksuite/view-extensions/editor-config/toolbar/index.ts— Controls which block flavours appear in the editor toolbar, including custom surface extensions. -
blocksuite/affine/blocks/**— Directory housing concrete implementations for each block type, including view components, data models, and service configurations (e.g.,blocksuite/affine/blocks/paragraph/src/view.ts). -
tests/blocksuite/e2e/**— End-to-end test suites demonstrating block instantiation viadoc.addBlock()for every flavour type. -
blocksuite/affine/widgets/keyboard-toolbar/src/config.ts— Defines slash-menu entries and embed configurations for external content blocks (lines 1005-1115).
Summary
- AFFiNE's editor supports 20+ built-in block types identified by
affine:-prefixed flavour strings, built on the BlockSuite framework. - Container blocks (
affine:page,affine:note) provide the hierarchical structure for all documents. - Content blocks include paragraphs, lists (bulleted/numbered/todo), code blocks with syntax highlighting, dividers, images, and bookmarks.
- Embed blocks support external integrations including YouTube, Figma, GitHub, generic iframes, and linked/synced AFFiNE documents.
- Edgeless blocks (
affine:surface,affine:surface-ref) enable whiteboard and canvas functionality. - Database blocks (
affine:database) provide structured table and list views, whileaffine:todorepresents checklist variants. - Developers can create blocks programmatically using
doc.addBlock(flavour, props, parentId)as demonstrated in the BlockSuite test suite.
Frequently Asked Questions
What is the difference between affine:page and affine:note blocks?
The affine:page block serves as the root container for every AFFiNE document, representing the top-level page entity in the BlockSuite document model. The affine:note block functions as a generic content container that lives inside pages, holding paragraphs, images, and other content blocks. While every document has exactly one page root, it can contain multiple note blocks to create complex document layouts, as shown in tests/blocksuite/e2e/zero-width.spec.ts (lines 46, 49).
How do I create a todo list programmatically in AFFiNE?
Todo lists are created using the affine:list flavour with the type property set to 'todo'. Using the BlockSuite API, call doc.addBlock('affine:list', { type: 'todo' }, parentNoteId) where parentNoteId references the containing note block. This renders as an interactive checklist with toggleable checkboxes, distinct from bulleted or numbered list variants, as demonstrated in tests/blocksuite/e2e/list.spec.ts (line 80).
What is the difference between embed-linked-doc and embed-synced-doc?
The affine:embed-linked-doc block creates a static inline view of another AFFiNE page at the time of insertion, functioning as a snapshot reference to the linked content. The affine:embed-synced-doc block maintains a live synchronization with the source document, automatically updating the embedded content whenever the original page changes. Both are configured in blocksuite/affine/widgets/keyboard-toolbar/src/config.ts at lines 1073 and 1115 respectively.
Can I create custom block types in AFFiNE?
Yes, AFFiNE supports custom block flavours that extend the core affine: namespace or use custom prefixes like custom:affine:surface:bookmark. These are registered through the BlockSuite schema system and can be added to the toolbar via packages/frontend/core/src/blocksuite/view-extensions/editor-config/toolbar/index.ts. Custom blocks require implementing the corresponding view, model, and service classes following the BlockSuite block definition pattern established in the blocksuite/affine/blocks/ directory structure.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →