Skip to content

Redactor 4 Configuration Guide

Last Updated: January 2026
Related Files:

  • client/js/crm/editors/redactor4.js - Base configurations and plugins
  • app/javascript/controllers/redactor4_init_controller.js - Stimulus initialization
  • app/inputs/redactor_input.rb - SimpleForm custom input

Redactor 4 is the WYSIWYG editor used throughout the CRM for rich text editing. It supports multiple modes depending on the use case, from full-featured blog editing to minimal note-taking.


Feature Blog Email Default Air (Notes) Readonly
Base Options defaultRedactor4Options + aiRedactor4Options emailRedactor4Options defaultRedactor4Options simpleNotesRedactor4Options Any + disabled
Min Height 2000px 500px 300px 100px Inherited
Pathbar Hidden Hidden Hidden Hidden Hidden
Source Code Via data attr Via data attr Via data attr No No
Toolbar External (#redactor-blog-toolbar) Sticky (72px offset) Sticky (72px offset) Air (floating) Hidden
CSS Injection WWW styles CodeMirror custom CSS None None None
AI Tools
Context Menu

Plugin Blog Email Default Air Description
alignment Text alignment
counter Word/character count
fullscreen Fullscreen editing
imageresize Visual image resizing
fontcolor Text color
fontfamily Font family
fontsize Font size
blockcolor Block text color
blockbackground Block background
blockborder Block borders
blockfontsize Block font size
wyimage WY Image Library picker
wyembed oEmbed (YouTube, etc.)
wyvideo WY Video Library picker
wyfaq WY FAQ Library picker
ai OpenAI text/image tools
mergetag Liquid merge tags
clips Email snippets
variable Variable insertion
email Email formatting
wyemailblocks WY Header/Footer blocks

The Stimulus controller (redactor4_init_controller.js) detects which mode to use:

// In initializeRedactor4()
const isEmailEditor = editor.id === 'redactor-email-template-body-v4' ||
(this.hasEmailValue && this.emailValue);
const isBlogEditor = (this.hasBlogValue && this.blogValue) ||
editor.id === 'redactor-blog';
const isAirMode = this.hasAirValue && this.airValue;
  1. Air Mode - data-redactor4-init-air-value="true"
  2. Email Mode - editor.id === 'redactor-email-template-body-v4' OR data-redactor4-init-email-value="true"
  3. Blog Mode - editor.id === 'redactor-blog' OR data-redactor4-init-blog-value="true"
  4. Default Mode - Fallback

Used in: app/views/crm/posts/_content.html.erb

<div data-controller="redactor4-init"
data-redactor4-init-blog-value="true"
data-redactor4-init-source-value="<%= current_user&.admin? %>">
<%= f.input_field :solution,
id: 'redactor-blog',
class: 'form-control',
data: {
redactor4_init_target: 'editor',
www_css: webpack_css_url('www').to_json
} %>
</div>

Blog-specific features:

  • External toolbar in sticky header (#redactor-blog-toolbar)
  • WWW CSS injected for WYSIWYG preview
  • 2000px minimum height
  • AI tools, FAQ picker, Video picker enabled
  • blog-post-body class applied for styling

Used in: app/views/email_templates/_form.html.erb

<div data-controller="redactor4-init"
data-redactor4-init-email-value="true">
<%= f.text_area :body,
id: 'redactor-email-template-body-v4',
class: 'form-control',
data: { redactor4_init_target: 'editor' } %>
</div>

Email-specific features:

  • Liquid merge tags (recipient, sender, etc.)
  • Email clips (header, footer snippets)
  • WY Email Blocks plugin
  • Custom CSS injection from CodeMirror
  • Paste converts to plain text

Used in: Most forms via SimpleForm input

<%= f.input :description, as: :redactor %>

Or manually:

<div data-controller="redactor4-init">
<%= f.text_area :body,
class: 'form-control',
data: { redactor4_init_target: 'editor' } %>
</div>

Used in: Activity notes, comments

<div data-controller="redactor4-init"
data-redactor4-init-air-value="true">
<%= f.text_area :notes,
class: 'form-control',
data: { redactor4_init_target: 'editor' } %>
</div>

Air mode features:

  • Floating toolbar (appears on selection)
  • Minimal buttons: bold, italic, deleted, list
  • No plugins loaded
  • Plain text paste

Any mode can be made readonly:

<div data-controller="redactor4-init"
data-redactor4-init-readonly-value="true">
<%= f.text_area :preview,
class: 'form-control',
data: { redactor4_init_target: 'editor' } %>
</div>

Value Type Description
blog Boolean Enable blog mode with AI, FAQ, Video plugins
email Boolean Enable email mode with merge tags
air Boolean Enable minimal air mode (floating toolbar)
minHeight String Override minimum height (e.g., “500px”)
plugins Array Override plugin list
source Boolean Enable HTML source editing (admin only)
readonly Boolean Disable editing, hide toolbar
legacyBody String Legacy v3 content for migration

Image picker that integrates with the Image Library. Uses oEmbed API for rich HTML insertion.

Features:

  • Image search and selection
  • Visual cropping with Cropper.js
  • All ImageKit transformations (resize, rotate, blur, etc.)
  • Responsive srcset generation
  • Caption support
  • Re-editing existing images

Inserted HTML structure:

<figure class="wy-image-embed" data-wy-image-id="123" data-wy-image-options="{...}">
<img src="..." srcset="..." alt="..." loading="lazy" class="img-fluid">
<figcaption class="figure-caption">Caption here</figcaption>
</figure>

Video picker that integrates with the Video Library. Uses oEmbed API.

Blog only - Not available in email or default modes.

FAQ picker that embeds FAQ accordion blocks. Uses oEmbed API.

Blog only - Not available in email or default modes.

Enhanced oEmbed for external content (YouTube, Vimeo, etc.).

Not available in email mode - Email clients don’t support iframes.

Quick insertion of branded email header/footer.

Email only - Not available in other modes.


// Exported configurations:
window.defaultRedactor4Options // Standard editor
window.emailRedactor4Options // Email templates
window.aiRedactor4Options // AI + wyfaq + wyvideo (merged for blog)
window.simpleNotesRedactor4Options // Air mode

Default/Blog Mode:

  • clean: true - Sanitize for XSS protection
  • plaintext: false - Keep HTML formatting
  • stripAttr.allowedClasses - Whitelist of Bootstrap 5.3 + blog classes
  • stripAttr.allowedAttributes - Safe attributes only (no style)

Email Mode:

  • plaintext: true - Convert to plain text

Air Mode:

  • plaintext: true - Convert to plain text

The paste settings include a whitelist of allowed CSS classes for security:

  • Blog classes: blogLeft, blogRight, blog-cta, blog-post-body, etc.
  • Bootstrap 5.3: Spacing, display, flexbox, text, colors, tables, etc.
  • Redactor alignment: wrap-center, wrap-left, wrap-right, etc.

See defaultRedactor4Options.paste.stripAttr.allowedClasses for full list.


  1. Check browser console for errors
  2. Verify Stimulus controller is connected: 📝 Redactor4 Stimulus controller connected
  3. Check if element has correct data attributes
  4. Verify lazy loading: 📝 Redactor 4 module loaded
  1. For blog: Check #redactor-blog-toolbar exists in DOM
  2. For email/default: Check toolbar.stickyTopOffset is correct (72px for CRM navbar)
  3. For readonly: Toolbar is intentionally hidden
  1. Check plugin is in the correct options set
  2. Check browser console for plugin errors
  3. Verify plugin JS is imported in redactor4.js
  1. Verify Oembed::ImageProvider is handling crop params
  2. Check that crop dimensions aren’t being upscaled beyond their size
  3. Verify ImageKit transformation string is correct