This guide covers Redactor's block JSON format: loading structured content, exporting it, and the data fields each block type accepts.
For HTML strings (content option, getHtml, insertHtml), see Set & get content.
Document shape#
A Redactor document is a flat array of block objects:
[
{ type: 'heading', data: { level: 1, content: 'Title' } },
{ type: 'text', data: { content: '<p>Body paragraph.</p>' } }
]
Each item has:
| Field | Type | Description |
|---|---|---|
type |
string |
Block type (text, heading, image, …) |
data |
object |
Block properties (common + type-specific) |
Nested structures (layout columns, wrapper children) use a children array inside data. When you export with getJson(), parent blocks include serialized children.
Set JSON on init#
Pass a block array through the data option:
<div id="entry"></div>
const app = Redactor('#entry', {
data: [
{ type: 'heading', data: { level: 1, content: 'Hello' } },
{ type: 'text', data: { content: 'Loaded from JSON.' } }
]
});
data takes priority over host markup. If you also pass content, content wins (see the content guide).
Replace the whole document (API)#
app.setJson([
{ type: 'text', data: { content: 'New document.' } }
]);
Equivalent form:
app.setContent(blocks, { format: 'json', caret: 'end' });
caret works the same as for HTML: false, 'start', or 'end'.
Get JSON#
getJson()
Returns the current document as a block array (cleaned for export).
const blocks = app.getJson();
getContent('json')
Same result through the generic API:
const blocks = app.getContent('json');
getBlocks() and getNodes()
Lower-level access — mounted block instances or root DOM nodes rebuilt from JSON:
const blockInstances = app.getBlocks();
const nodes = app.getNodes();
Use these when you need to work with the editor internals, not for storage.
Output hooks#
Before JSON is returned, Redactor emits output:before:json with { json }. Change json in the handler to post-process export.
Common data fields#
Every block type can include these optional fields in data:
| Field | Type | Description |
|---|---|---|
id |
string |
Element id attribute |
styles |
object |
Inline styles as key/value pairs (camelCase CSS properties) |
classname |
string |
Extra CSS classes (space-separated) |
placeholder |
string |
Placeholder text where the block supports it |
attrs |
object |
Custom HTML attributes (data-*, aria-*, etc.) |
noneditable |
boolean |
When true, block content cannot be edited or deleted (data-noneditable="true") |
nondeletable |
boolean |
When true, block cannot be deleted but content stays editable (data-nondeletable="true") |
uid |
string |
Stable block UID (data-uid) |
time |
string |
Timestamp metadata (data-time) |
children |
array |
Nested blocks (layout, column, wrapper) — see below |
Omitted fields are not written on export.
Nested blocks (children)#
Blocks with children hold other blocks inside them:
Parent type |
Role |
|---|---|
layout |
Grid row with columns |
column |
Single column inside a layout |
wrapper |
Generic wrapper element around content |
On export, getJson() adds children automatically for these parents.
On import, you can either:
- Put nested blocks in
data.children(matches export), or - For
layoutonly — usedata.columns[].children(see layout).
{
type: 'wrapper',
data: {
wrap: 'section',
classname: 'callout',
children: [
{ type: 'text', data: { content: 'Inside the wrapper.' } }
]
}
}
Block types#
text
Paragraph or generic text block (<p> by default).
| Field | Type | Description |
|---|---|---|
content |
string |
Inner HTML |
{ type: 'text', data: { content: 'Plain text or <strong>HTML</strong>.' } }
{ type: 'text', data: { content: 'Locked.', noneditable: true } }
{ type: 'text', data: { content: 'Required slot.', nondeletable: true } }
heading
| Field | Type | Description |
|---|---|---|
level |
number |
Heading level 1–6 |
content |
string |
Inner HTML |
{ type: 'heading', data: { level: 2, content: 'Section title' } }
address
| Field | Type | Description |
|---|---|---|
content |
string |
Inner HTML |
{ type: 'address', data: { content: '221B Baker Street' } }
image
| Field | Type | Description |
|---|---|---|
src |
string |
Image URL (required) |
alt |
string |
alt attribute |
title |
string |
title attribute |
srcset |
string |
srcset attribute |
width |
string |
Width attribute |
height |
string |
Height attribute |
url |
string |
Link href when the image is wrapped in <a> |
target |
string |
Link target (_blank, etc.) |
caption |
string |
Figure caption text |
img |
object |
{ styles: { … } } — inline styles on the <img> element |
{
type: 'image',
data: {
src: '/uploads/photo.jpg',
alt: 'Sample',
url: 'https://example.com',
target: '_blank',
caption: 'Photo caption'
}
}
list
Bullet or numbered list.
| Field | Type | Description |
|---|---|---|
items |
array |
List items (see below) |
numbered |
boolean |
true for ordered list (<ol>) |
Each item in items:
| Field | Type | Description |
|---|---|---|
content |
string |
Item HTML |
items |
array |
Nested sub-list (same shape, recursive) |
{
type: 'list',
data: {
numbered: true,
items: [
{ content: 'First item' },
{ content: 'Second item', items: [{ content: 'Nested item' }] }
]
}
}
todo
Checkbox task list.
| Field | Type | Description |
|---|---|---|
items |
array |
Todo items |
Each item:
| Field | Type | Description |
|---|---|---|
content |
string |
Task HTML |
done |
boolean |
Checked state |
items |
array |
Nested sub-tasks (recursive) |
{
type: 'todo',
data: {
items: [
{ content: 'Ship feature', done: true },
{ content: 'Write docs', done: false }
]
}
}
table
| Field | Type | Description |
|---|---|---|
items |
array |
2D array of rows; each row is an array of cell HTML strings |
head |
boolean |
First row(s) from items are treated as <thead> when true |
foot |
boolean |
Last row(s) are treated as <tfoot> when true |
caption |
object | string |
Table caption — string shorthand or { content, placeholder? } |
{
type: 'table',
data: {
head: true,
items: [
['Name', 'Role'],
['Ada', 'Engineer'],
['Grace', 'Scientist']
],
caption: 'Team members'
}
}
dlist
Definition list (<dl>).
| Field | Type | Description |
|---|---|---|
items |
array |
Pairs of term and description |
Each item:
| Field | Type | Description |
|---|---|---|
term |
string |
<dt> text |
desc |
string |
<dd> text |
{
type: 'dlist',
data: {
items: [
{ term: 'API', desc: 'Application Programming Interface' },
{ term: 'CMS', desc: 'Content Management System' }
]
}
}
quote
| Field | Type | Description |
|---|---|---|
content |
string |
Quote body HTML |
caption |
string |
Optional citation / author line |
{
type: 'quote',
data: {
content: 'The only way to do great work is to love what you do.',
caption: 'Steve Jobs'
}
}
pre
Code or preformatted block.
| Field | Type | Description |
|---|---|---|
content |
string |
Code text (HTML entities allowed) |
caption |
string |
Optional caption below the block |
text is accepted as an alias for content on import.
{ type: 'pre', data: { content: 'const x = 1;' } }
details
Collapsible <details> block.
| Field | Type | Description |
|---|---|---|
summary |
string |
Summary line (plain text) |
content |
string |
Body text after the summary (plain text) |
open |
boolean |
Expanded by default |
{
type: 'details',
data: {
summary: 'More information',
content: 'Hidden details text.',
open: false
}
}
embed
Video, audio, or iframe embed.
| Field | Type | Description |
|---|---|---|
type |
string |
Media tag: iframe, video, audio, … |
src |
string |
Media URL |
html |
string |
Raw embed HTML (alternative to src) |
width |
string |
Width attribute |
height |
string |
Height attribute |
caption |
string |
Caption text |
wrap |
boolean |
Wrapped in a figure |
responsive |
boolean |
Responsive wrapper applied |
{
type: 'embed',
data: {
type: 'iframe',
src: 'https://www.youtube.com/embed/…',
width: '560',
height: '315',
responsive: true
}
}
layout
Multi-column grid.
| Field | Type | Description |
|---|---|---|
pattern |
string |
Column widths, pipe-separated — e.g. '50%|50%' or '33%|33%|33%' |
columns |
array |
Explicit columns (alternative to pattern) |
grid |
string |
CSS class for the grid container |
column |
string |
CSS class applied to every column |
children |
array |
Column blocks (export format) |
Each entry in columns:
| Field | Type | Description |
|---|---|---|
width |
string |
Column width (flex-basis, e.g. '50%') |
classname |
string |
Extra class for this column |
children |
array |
Blocks inside the column |
{
type: 'layout',
data: {
pattern: '50%|50%',
columns: [
{ width: '50%', children: [{ type: 'text', data: { content: 'Left' } }] },
{ width: '50%', children: [{ type: 'text', data: { content: 'Right' } }] }
]
}
}
column
A single column — usually nested inside layout via children. Rarely used as a top-level block.
| Field | Type | Description |
|---|---|---|
width |
string |
Column width (flex-basis) |
children |
array |
Blocks inside the column |
wrapper
Groups blocks in a custom wrapper element.
| Field | Type | Description |
|---|---|---|
wrap |
string |
HTML tag name (div, section, …) |
children |
array |
Nested blocks |
{
type: 'wrapper',
data: {
wrap: 'aside',
classname: 'sidebar',
children: [
{ type: 'text', data: { content: 'Sidebar note.' } }
]
}
}
noneditable
Fixed HTML the user cannot edit in the UI.
| Field | Type | Description |
|---|---|---|
content |
string |
Inner HTML |
{ type: 'noneditable', data: { content: '<span>Locked badge</span>' } }
mergetag
Inline merge field / variable token.
| Field | Type | Description |
|---|---|---|
content |
string |
Tag label (plain text) |
{ type: 'mergetag', data: { content: '' } }
Usually appears inside text or heading content HTML rather than as a separate top-level block.
line
Horizontal rule (<hr>). No type-specific fields — common data only.
{ type: 'line' }