Replace Knack's editor with QUILL - you'll love it

Replacing Redactor with Quill in Knack — a better rich text editor

If you’ve ever been frustrated with Knack’s chosen editor Redactor’s paste behaviour, paragraph spacing, or limited toolbar control, here’s how to swap it out for Quill — a modern, open-source rich text editor that handles paste cleanly, renders consistently, and is much easier to customise.

What this gives you:

  • Clean paste from Word, Excel, web pages — formatting is stripped to what Quill supports, no more <p> tag chaos
  • Consistent line spacing between the editor and rendered detail views
  • Proper bold, italic, underline, strikethrough that latch correctly when typing
  • Font size, text colour and background colour pickers
  • Easy toolbar customisation
  • Works globally across all rich text fields in your app

JavaScript

/************************************************************************
QUILL RICH TEXT EDITOR - REPLACES REDACTOR
*************************************************************************/
(function() {
var link = document.createElement(‘link’);
link.rel = ‘stylesheet’;
link.href = ‘https://cdn.quilljs.com/1.3.7/quill.snow.css’;
document.head.appendChild(link);

var script = document.createElement(‘script’);
script.src = ‘https://cdn.quilljs.com/1.3.7/quill.min.js’;
script.onload = function() {
$(document).on(‘knack-view-render.any’, function() {
initQuillEditors();
});
};
document.head.appendChild(script);
})();

function initQuillEditors() {
$(‘.redactor-box’).each(function() {
var $box = $(this);

if ($box.data('quill-init')) return;
$box.data('quill-init', true);

var $textarea = $box.find('textarea');
var $redactorEditor = $box.find('.redactor-editor');

var existingContent = $textarea.val() || $redactorEditor.html() || '';

$redactorEditor.hide();
$box.find('.redactor-toolbar').hide();

var $quillContainer = $('<div class="quill-container"></div>');
$box.append($quillContainer);

var quill = new Quill($quillContainer[0], {
  theme: 'snow',
  modules: {
    toolbar: [
      ['bold', 'italic', 'underline', 'strike'],
      [{ list: 'ordered' }, { list: 'bullet' }],
      [{ size: ['small', false, 'large', 'huge'] }],
      [{ color: [] }, { background: [] }],
      ['clean']
    ]
  }
});

if (existingContent) {
  quill.clipboard.dangerouslyPasteHTML(existingContent);
}

quill.on('text-change', function() {
  var html = $quillContainer.find('.ql-editor').html();
  $textarea.val(html);
  $textarea.trigger('change');
});

});
}

CSS:

/* Quill editor container */
.quill-container {
border: 1px solid #ccc;
border-radius: 4px;
}

/* Toolbar styling */
.ql-toolbar {
background: #eaecfa;
border-radius: 4px 4px 0 0;
padding: 2px !important;
}
.ql-toolbar button {
width: 24px !important;
height: 24px !important;
padding: 2px !important;
}
.ql-toolbar button svg {
width: 14px !important;
height: 14px !important;
}
.ql-toolbar .ql-picker {
font-size: 12px !important;
}

/* Editor area */
.ql-container {
font-size: 14px;
min-height: 120px;
}
.ql-editor {
min-height: 120px;
}

/* Shrink paragraph spacing in editor */
.ql-editor p {
margin: 0 !important;
line-height: 1.4 !important;
}

/* Shrink paragraph spacing in detail/rendered views */
.kn-detail-body p {
margin: 0 !important;
line-height: 1.4 !important;
}

/* Fix background colour span rendering in detail views to avoid line split */
.kn-detail-body span[style=“background-color”] {
display: inline !important;
}

Customising the toolbar

The toolbar is configured in the JavaScript as an array of arrays. Each inner array becomes a button group separated by a divider. Here are all the available options:

Option What it does
'bold' Bold
'italic' Italic
'underline' Underline
'strike' Strikethrough
'link' Insert hyperlink
'clean' Remove all formatting from selection
{ list: 'ordered' } Numbered list
{ list: 'bullet' } Bullet list
{ indent: '-1' } Outdent
{ indent: '+1' } Indent
{ size: ['small', false, 'large', 'huge'] } Font size picker
{ color: [] } Text colour picker
{ background: [] } Background colour picker
{ align: [] } Text alignment
{ header: 1 } Heading 1
{ header: 2 } Heading 2
'blockquote' Block quote
'code-block' Code block

Example — minimal toolbar (bold, italic, underline, lists only):

toolbar: [
[‘bold’, ‘italic’, ‘underline’],
[{ list: ‘ordered’ }, { list: ‘bullet’ }],
[‘clean’]
]

Example — full featured toolbar:

toolbar: [
[‘bold’, ‘italic’, ‘underline’, ‘strike’],
[{ list: ‘ordered’ }, { list: ‘bullet’ }],
[{ indent: ‘-1’ }, { indent: ‘+1’ }],
[{ size: [‘small’, false, ‘large’, ‘huge’] }],
[{ color: [] }, { background: [] }],
[{ align: [] }],
[‘link’, ‘clean’]
]


Notes

  • Applies to Knack CLASSIC only
  • Content is saved as standard HTML to the Knack textarea, so existing Redactor content continues to render correctly
  • If you have specific views where you want a larger editor (e.g. comment modals), scope the min-height to those view IDs
  • KTL compatibility — seems to work in apps using KTL, and Carig says he has been using this for some time so should be good to go.
  • If you find issues or improvements, please share back in the thread

Enjoy, I hope this is of value to someone - it certainly fixed some headaches for me, especially with pasting content into Knack rick text fields.

3 Likes