Redactor supports three ways to protect content. Each restricts editing, deletion, or both in predictable ways — across clicks, keyboard, selection, and control menus.
| Type | Markup | Content editable | Block deletable |
|---|---|---|---|
| Non-editable wrapper | data-block="noneditable" |
No (inside wrapper) | Yes by default* |
| Non-editable block | data-noneditable="true" |
No | No |
| Non-deletable block | data-nondeletable="true" |
Yes | No |
* Set noneditable.remove: false to prevent deleting the wrapper.
Non-editable wrapper (NonEditableBlock)#
A wrapper block that locks everything inside. Use it for pre-rendered fragments, embed shells, legal notices, or imported HTML the author must not change.
Markup
<div data-block="noneditable">
<h2>Terms summary</h2>
<p>This section is locked.</p>
</div>
Load at init:
const app = Redactor('#entry', {
content: '<div data-block="noneditable"><p>Locked notice.</p></div>'
});
Or insert via JSON:
{
type: 'noneditable',
data: {
content: '<h2>Notice</h2><p>Do not edit.</p>'
}
}
The wrapper has contenteditable="false". Inner HTML is stored as plain markup — child elements are not separate editable blocks.
Behavior
- No editing inside — no typing, formatting, insertion, or deletion within the wrapper.
- Caret cannot enter the wrapper; focus treats it as one unit.
- Insert before/after — new blocks can be added above or below, never inside.
- Selection — the wrapper can be selected (block handle, click).
- Delete — by default the wrapper can be removed with Backspace/Delete when focused. Control bar Delete and Duplicate are hidden for this block type.
- Enter — inserts a new paragraph after the wrapper, not inside it.
Example: Non-editable wrapper.
Setting — noneditable.remove
Default: true (wrapper can be deleted)
const app = Redactor('#entry', {
noneditable: {
remove: false
}
});
With remove: false:
- The wrapper cannot be deleted from the control menu or with Backspace/Delete.
- Delete/Duplicate stay hidden in the control bar.
Note: If the user selects all editor content and deletes it, protected blocks may still be removed together with everything else. Do not rely on remove: false as a hard server-side boundary — validate on save.
Non-editable blocks#
Fully protected blocks: content cannot be edited and the block cannot be deleted. Use for locked instructions, imported components, or atomic template pieces.
Markup
On a single block:
<p data-noneditable="true">This paragraph cannot be edited or removed.</p>
On a wrapper (inner blocks stay mounted, but the region is locked):
<div data-noneditable="true">
<p>Locked content inside…</p>
</div>
At runtime on the current block:
app.block.setNonEditable();
// …
app.block.clearNonEditable();
In JSON, use the common field noneditable: true on any block type (see JSON).
Example: Non-editable block.
Behavior
- No editing inside — no typing, formatting, insertion, or deletion of content.
- Caret cannot be placed inside the block.
- Nothing inserted inside — only before or after the block.
- Context bar does not appear when this block is selected.
- Control bar — Delete is hidden (
isProtected()). - Keyboard — Backspace/Delete does not remove the block.
- Multi-block selection — if the selection includes a protected block, bulk delete is ignored.
This is the strictest mode — a fully protected, atomic block.
Non-deletable blocks#
The block stays in the document, but content inside remains editable. Use for persistent structural elements (fixed intro, required disclaimer paragraph, template slot) where text may change but the block itself must not be removed.
Markup
On a single block:
<p data-nondeletable="true">This block cannot be removed, but you can edit this text.</p>
On a wrapper:
<div data-nondeletable="true">
<p>Editable content inside…</p>
</div>
With placeholder on an empty paragraph:
<p data-nondeletable="true" data-placeholder="Type anything…"></p>
At runtime:
app.block.setNonDeletable();
// …
app.block.clearNonDeletable();
In JSON, use the common field nondeletable: true on any block type (see JSON).
Example: Non-deletable block.
Behavior
- Content is editable — typing, deleting text, formatting, and inline changes work inside the block.
- Block cannot be deleted — not with Backspace/Delete at block edges, not from the control menu, not via Cut when it would remove the block.
- Multi-block delete — if the selection includes a non-deletable block, the delete operation is cancelled.
- Enter — does not split the block into two; Enter affects only inner content (e.g. new line inside a paragraph), not the wrapper boundary.
- Last block — if it is the only block in the editor, it is never removed when the document would otherwise become empty.
Choose the right mode#
| Goal | Use |
|---|---|
| Lock a HTML fragment (banner, embed, legal text) | data-block="noneditable" wrapper |
| Lock wrapper and prevent its removal | data-block="noneditable" + noneditable.remove: false |
| Fixed block users may edit but not delete | data-nondeletable="true" |
| Block and content fully frozen | data-noneditable="true" |
You can combine attributes on the same element when needed — data-noneditable implies non-deletable behavior for editing; for “editable but not removable” use only data-nondeletable.
API#
| Method | Description |
|---|---|
app.block.setNonEditable() |
Mark current block data-noneditable="true" |
app.block.clearNonEditable() |
Remove non-editable flag |
app.block.isNonEditable() |
Check data-noneditable |
app.block.setNonDeletable() |
Mark current block data-nondeletable="true" |
app.block.clearNonDeletable() |
Remove non-deletable flag |
app.block.isNonDeletable() |
Check data-nondeletable |
See block module.
JSON#
noneditable and nondeletable are common block fields — the same level as id, classname, and placeholder. On save they become data-noneditable="true" / data-nondeletable="true" on the block root element.
Redactor('#entry', {
data: [
{ type: 'text', data: { content: '<p>Editable paragraph.</p>' } },
{
type: 'noneditable',
data: { content: '<p><strong>Locked</strong> notice.</p>' }
},
{
type: 'text',
data: {
content: '<p>Fully frozen paragraph.</p>',
noneditable: true
}
},
{
type: 'text',
data: {
content: '<p>Editable but cannot be deleted.</p>',
nondeletable: true
}
}
]
});
getJson() exports these flags as noneditable: true / nondeletable: true in data (omitted when false).
You can still load protection via HTML attributes when using the content option:
Redactor('#entry', {
content: '<p data-noneditable="true">Protected paragraph.</p>'
});