<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Untitled Publication]]></title><description><![CDATA[Untitled Publication]]></description><link>https://auwalms.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 22 Sep 2026 17:13:43 GMT</lastBuildDate><atom:link href="https://auwalms.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Integrate Quilljs WYSIWYG Editor in Your Phoenix Project]]></title><description><![CDATA[In this article, we will outline steps for adding Quilljs, a free, open-source What-You-See-Is-What-You-Get (WYSIWYG) editor, to a Phoenix project to enhance users' experience when creating content that requires formatting. Let's get started.
I assum...]]></description><link>https://auwalms.hashnode.dev/how-to-integrate-quilljs-wysiwyg-editor-in-your-phoenix-project</link><guid isPermaLink="true">https://auwalms.hashnode.dev/how-to-integrate-quilljs-wysiwyg-editor-in-your-phoenix-project</guid><category><![CDATA[Elixir]]></category><category><![CDATA[Phoenix framework]]></category><category><![CDATA[quilljs]]></category><category><![CDATA[integration]]></category><dc:creator><![CDATA[Auwal MS]]></dc:creator><pubDate>Sat, 31 Aug 2024 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p>In this article, we will outline steps for adding <a target="_blank" href="https://quilljs.com/">Quilljs</a>, a free, open-source What-You-See-Is-What-You-Get (WYSIWYG) editor, to a <a target="_blank" href="https://www.phoenixframework.org/">Phoenix</a> project to enhance users' experience when creating content that requires formatting. Let's get started.</p>
<p>I assume you already have an elixir project you want to implement this on, but for the sake of this guide, let's bootstrap one for this from our terminal/CLI.</p>
<pre><code class="lang-elixir">mix phx.new quill_to_phoenix_demo
<span class="hljs-comment"># Hit Enter when prompted to "Fetch and install dependencies? [Yn]"</span>
</code></pre>
<p>I will set up the database using this command <code>mix ecto.setup</code> and run the initial migration. Next, let us use the <a target="_blank" href="https://hexdocs.pm/phoenix/mix_tasks.html">Mix generator</a> to create the HTML boilerplate of our project using <code>mix phx.gen.html Blog Post posts title:string body:string</code>. Once we add our resource path <code>resources "/posts", PostController</code> to the router file <code>lib/quill_to_phoenix_demo_web/router.ex</code> and run our migration (<code>mix ecto.migrate</code>) so that the post table will be created in our database. We should be up and ready.</p>
<p>Running our server using <code>iex -S mix phx.server</code> and navigating to <a target="_blank" href="http://localhost:4000/posts/">http://localhost:4000/posts/</a> and then clicking <strong>New Post</strong> will show us a basic form like what we have below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724578572335/55e86294-4621-4a58-ba56-ca63ddc7bbcd.webp" alt class="image--center mx-auto" /></p>
<p>On the left is what we currently have, and on the right is our destination</p>
<h3 id="heading-step-1-add-quill-to-the-project">Step 1: Add Quill to the project</h3>
<p>We have two options:</p>
<ol>
<li><p>Install it as an NPM package by running <code>npm install quill</code> in your assets directory</p>
</li>
<li><p>Use CDN to add it globally to your project by adding t.</p>
</li>
</ol>
<p>In this guide, we will be using the second option by adding the below code to <code>root.html.heex</code>.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/quill@2.0.2/dist/quill.js"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h3 id="heading-step-2-add-quill-css-to-your-project">Step 2: Add Quill CSS to your Project</h3>
<p>To ensure your WYSIWYG editor looks like what we want, you need to add the quill's CSS CDN to our <code>root.html.heex</code>.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/quill@latest/dist/quill.snow.css"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> /&gt;</span>
</code></pre>
<p><em>If you used option 2 in the first step, ensure this CSS link comes before your JS.</em></p>
<h3 id="heading-step-3-initialize-quill-in-your-project">Step 3: Initialize Quill in your project</h3>
<p>Now that we've added both the JS and CSS to our project, it is time to initialize the quill package in our project, and we will do that by adding the following code to our <code>hook.js</code> file, which can be found in <code>/assets/js/</code> folder (If it doesn't exist, create one).</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//import Quill from 'quill'; </span>
<span class="hljs-comment">//uncomment the above line if you added quill to the project using npm</span>

<span class="hljs-keyword">let</span> Hooks = {};

Hooks.QuillEditor = {
    mounted() {
        <span class="hljs-built_in">this</span>.initializeQuill();
    },
    updated() {
        <span class="hljs-built_in">this</span>.initializeQuill();
    },
    initializeQuill() {


        <span class="hljs-built_in">this</span>.quill = <span class="hljs-keyword">new</span> Quill(<span class="hljs-string">'#editor-container'</span>, {
            <span class="hljs-attr">theme</span>: <span class="hljs-string">'snow'</span>,
            <span class="hljs-attr">placeholder</span>: <span class="hljs-string">'Type your content here...'</span>,
            <span class="hljs-attr">modules</span>: {
                <span class="hljs-comment">//customization happens here</span>
            }
        });

        <span class="hljs-keyword">const</span> hiddenInput = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'hidden-content'</span>);

        <span class="hljs-built_in">this</span>.quill.root.innerHTML = hiddenInput.value;
        <span class="hljs-built_in">this</span>.quill.on(<span class="hljs-string">'text-change'</span>, <span class="hljs-function">() =&gt;</span> {
            hiddenInput.value = <span class="hljs-built_in">this</span>.quill.root.innerHTML;
        });
    }
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Hooks;
</code></pre>
<p>You also need to import hooks.js into the <code>app.js</code> file and add it to the liveSocket's third parameter object as such</p>
<pre><code class="lang-javascript">...
import topbar <span class="hljs-keyword">from</span> <span class="hljs-string">"../vendor/topbar"</span>
<span class="hljs-keyword">import</span> Hooks <span class="hljs-keyword">from</span> <span class="hljs-string">"./hooks"</span> <span class="hljs-comment">//add this</span>

<span class="hljs-keyword">let</span> csrfToken = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"meta[name='csrf-token']"</span>).getAttribute(<span class="hljs-string">"content"</span>)
<span class="hljs-keyword">let</span> liveSocket = <span class="hljs-keyword">new</span> LiveSocket(<span class="hljs-string">"/live"</span>, Socket, {
  <span class="hljs-attr">longPollFallbackMs</span>: <span class="hljs-number">2500</span>,
  <span class="hljs-attr">hooks</span>: Hooks, <span class="hljs-comment">//add this as well</span>
  <span class="hljs-attr">params</span>: {<span class="hljs-attr">_csrf_token</span>: csrfToken}
})
...
</code></pre>
<p><strong>Step 4: Connect HTML/Heex form to connect to hook</strong></p>
<p>Here, we will be adding an empty <code>&lt;div id="editor-container" phx-hook="QuillEditor"&gt;&lt;/div&gt;</code> that serves as the container of our editor and is connected to the hook we created in Step 3. The existing input for the body must be changed to a hidden input field to keep all entries in the editor box and transmit the input when submitting the form. Our input field and div will look like the below code in the form.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">.simple_form</span> <span class="hljs-attr">:let</span>=<span class="hljs-string">{f}</span> <span class="hljs-attr">for</span>=<span class="hljs-string">{@changeset}</span> <span class="hljs-attr">action</span>=<span class="hljs-string">{@action}</span>&gt;</span>
...
  <span class="hljs-tag">&lt;<span class="hljs-name">.input</span> <span class="hljs-attr">field</span>=<span class="hljs-string">{f[:body]}</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">label</span>=<span class="hljs-string">"Body"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"hidden-content"</span>/&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"editor-container"</span> <span class="hljs-attr">phx-hook</span>=<span class="hljs-string">"QuillEditor"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
...
<span class="hljs-tag">&lt;/<span class="hljs-name">.simple_form</span>&gt;</span>
</code></pre>
<p>Congratulations. Your project should have the editor up and running, but let's customize it more. Everything after this is optional.</p>
<h3 id="heading-step-5-increase-the-toolbar-option-of-your-editor">Step 5: Increase the Toolbar Option of your Editor</h3>
<p>Quills API allows us to customize our editor as much as we want. To achieve the formatting option we've seen at the beginning of this guide, we need to add the following codes to the <code>initializeQuill()</code> node of our <code>hooks.js</code> file</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> toolbarOptions = [
            [ { <span class="hljs-string">'size'</span>: [] }],
            [{ <span class="hljs-string">'header'</span>: [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-literal">false</span>] }],
            [<span class="hljs-string">'bold'</span>, <span class="hljs-string">'italic'</span>, <span class="hljs-string">'underline'</span>, <span class="hljs-string">'strike'</span>],
            [{ <span class="hljs-string">'color'</span>: [] }, { <span class="hljs-string">'background'</span>: [] }],
            [{ <span class="hljs-string">'script'</span>: <span class="hljs-string">'sub'</span> }, { <span class="hljs-string">'script'</span>: <span class="hljs-string">'super'</span> }],
            [{ <span class="hljs-string">'list'</span>: <span class="hljs-string">'ordered'</span> }, { <span class="hljs-string">'list'</span>: <span class="hljs-string">'bullet'</span> }],
            [{ <span class="hljs-string">'indent'</span>: <span class="hljs-string">'-1'</span> }, { <span class="hljs-string">'indent'</span>: <span class="hljs-string">'+1'</span> }],
            [{ <span class="hljs-string">'direction'</span>: <span class="hljs-string">'rtl'</span> }],
            [{ <span class="hljs-string">'align'</span>: [] }],
            [<span class="hljs-string">'link'</span>, <span class="hljs-string">'image'</span>, <span class="hljs-string">'video'</span>],
            [<span class="hljs-string">'clean'</span>]
        ];
</code></pre>
<p>Then, let us change our initialization of the quill editor to have <code>toolbar</code> as a child of the empty <code>module</code> object as seen below.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">this</span>.quill = <span class="hljs-keyword">new</span> Quill(<span class="hljs-string">'#editor-container'</span>, {
            <span class="hljs-attr">theme</span>: <span class="hljs-string">'snow'</span>,
            <span class="hljs-attr">placeholder</span>: <span class="hljs-string">'Type your content here...'</span>,
            <span class="hljs-attr">modules</span>: {
                <span class="hljs-attr">toolbar</span>: toolbarOptions <span class="hljs-comment">//this was added</span>
            }
        });
</code></pre>
<p>You can see other customization options on the <a target="_blank" href="https://quilljs.com/docs/modules/toolbar">Quill documentation page</a>.</p>
<p>Finally, remember to change your view to display the raw HTML created using the editor to avoid having HTML tags flying around.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724587226444/4495c9eb-b93d-4435-ab30-5ecd501faaf5.gif" alt class="image--center mx-auto" /></p>
]]></content:encoded></item></channel></rss>