How to Install and Use Trix Editor in Laravel

To manage content on the website, we always need a rich text editor(WYSIWYG). The rich text content requires HTML tags that can be added only through the WYSIWYG editor. The textarea tag can’t handle content wrapped inside HTML.

There are numerous rich text editors – TinyMCE, CKEditor available on the Internet. Trix Editor is one of them. It is developed by Basecamp. The Trix editor is being used in Basecamp for managing content. This is enough to say about the reliability of this WYSIWYG editor.

The focus of this article is to show you how to install and use the Trix editor in Laravel. We will also see how to upload images in the Trix editor. Following this tutorial, you’ll be able to handle rich text content in your Laravel application.

Installation of Trix Editor

For getting started with Trix, you first need to include their JS and CSS files. Get these files from the dist directory of their official Github page. Download the trix.js and trix.css files.

As we need to include the above assets, create a js and css folder inside the public directory of your Laravel project. Place the copied JS and CSS files in respective directories.

Uploading images on the server using Trix requires custom JavaScript code. Create the attachments.js file and keep it under the public/js folder. We will add code to this file in the later part of the tutorial.

Next, let’s define the Laravel routes. We have to achieve 3 tasks.

  • Display Trix Editor
  • Upload images in Trix Editor
  • Handle content submitted via Trix Editor

The following routes will handle these tasks.

Route::get('/trix', 'TrixController@index');
Route::post('/upload', 'TrixController@upload');
Route::post('/store', 'TrixController@store');

Create a TrixController using the Artisan command:

php artisan make:controller TrixController

The boilerplate of TrixController would be as follows.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TrixController extends Controller
{
    public function index()
    {
        return view('trix');
    }

    public function store(Request $request)
    {
    }

    public function upload(Request $request)
    {
    }
}

Display Trix Editor

Now, create a trix.blade file and add the following HTML to it. It will display the Trix editor.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <link rel="stylesheet" href="{{ asset('/css/trix.css') }}">
</head>
<body>
    <form method="post" action={{ url('store') }}>
        @csrf
        <p>
            <input id="x" type="hidden" name="content" value="" />
            <trix-editor input="x" class="trix-content"></trix-editor>
        </p>
        <input type="submit" name="submit" value="Submit" />
    </form>
     
    <script src="{{ asset('js/trix.js') }}"></script>
    <script src="{{ asset('js/attachments.js') }}"></script>
</body>
</html>

The Trix editor will be shown like the screenshot below.

Trix Editor

We placed the Trix editor in HTML using the trix-editor tag. The hidden field will be used to get or show content in Trix editor. This hidden field has the id “x” which is referenced exactly in the editor’s input attribute. When we type anything inside Trix, the content is set to the value of this hidden field. On the server side, we get the content of the Trix editor using the below code.

public function store(Request $request)
{
    echo $request->input('content');
}

If you want to populate content in Trix, set the value to the hidden field as

<input id="x" type="hidden" name="content" value="<h1>This is content</h1>" />

Upload Image in Trix Editor

To add images in the Trix editor, you need to upload them on the server. Trix editor provides an event trix-attachment-add through which we can upload the image via Ajax. We have added the upload route for it. Let’s define a method mapped with this route.

public function upload(Request $request)
{
    if($request->hasFile('file')) {
        //get filename with extension
        $filenamewithextension = $request->file('file')->getClientOriginalName();

        //get filename without extension
        $filename = pathinfo($filenamewithextension, PATHINFO_FILENAME);

        //get file extension
        $extension = $request->file('file')->getClientOriginalExtension();

        //filename to store
        $filenametostore = $filename.'_'.time().'.'.$extension;

        //Upload File
        $request->file('file')->storeAs('public/uploads', $filenametostore);

        // you can save image path below in database
        $path = asset('storage/uploads/'.$filenametostore);

        echo $path;
        exit;
    }
}

Here, I am storing images under the public/uploads directory. Create a symbolic link to the storage folder using the command:

php artisan storage:link

The attachments.js file will be used to give an Ajax call on the trix-attachment-add event. The following code will handle the Ajax request and response.

attachments.js

(function() {
    var HOST = "http://localhost:8000/upload"; //pass the route
 
    addEventListener("trix-attachment-add", function(event) {
        if (event.attachment.file) {
            uploadFileAttachment(event.attachment)
        }
    })
 
    function uploadFileAttachment(attachment) {
        uploadFile(attachment.file, setProgress, setAttributes)
 
        function setProgress(progress) {
            attachment.setUploadProgress(progress)
        }
 
        function setAttributes(attributes) {
            attachment.setAttributes(attributes)
        }
    }
 
    function uploadFile(file, progressCallback, successCallback) {
        var formData = createFormData(file);
        var xhr = new XMLHttpRequest();
         
        xhr.open("POST", HOST, true);
        xhr.setRequestHeader( 'X-CSRF-TOKEN', getMeta( 'csrf-token' ) );
 
        xhr.upload.addEventListener("progress", function(event) {
            var progress = event.loaded / event.total * 100
            progressCallback(progress)
        })
 
        xhr.addEventListener("load", function(event) {
            var attributes = {
                url: xhr.responseText,
                href: xhr.responseText + "?content-disposition=attachment"
            }
            successCallback(attributes)
        })
 
        xhr.send(formData)
    }
 
    function createFormData(file) {
        var data = new FormData()
        data.append("Content-Type", file.type)
        data.append("file", file)
        return data
    }
 
    function getMeta(metaName) {
        const metas = document.getElementsByTagName('meta');
       
        for (let i = 0; i < metas.length; i++) {
          if (metas[i].getAttribute('name') === metaName) {
            return metas[i].getAttribute('content');
          }
        }
       
        return '';
      }
})();

I have assigned the upload route to the HOST variable. Laravel requires a CSRF token for each request. I am getting this token from the meta tag added in the blade file. When you add the image in Trix, it triggers the Ajax call, uploads the image on the server, and returns the path of the uploaded image. This image then appends in the Trix editor. You can add styling to these images using the trix-content class given to the trix-editor tag.

.trix-content img {
    width: 300px;
    height: 300px;
}

I hope you understand how to install and use the Trix editor in Laravel. Check out the documentation to read more about the Trix editor.

If you liked this article, then please subscribe to our YouTube Channel for video tutorials.

1 thought on “How to Install and Use Trix Editor in Laravel

  1. Hallo, this has been an excelent tutorial.
    I’d like to know te proper way to remove the file listening to the ” trix-attachment-remove ” event. I’m using Laravel 8.
    Also, I’d like to store the path with te foreignKey related, in order to be able to authorize the access to the corresponding user.
    As you might imagine, I feel confortable with Laravel and PHP, but not so much bith javascript.
    Thanks anyway. Best regards. Hern’an.

Leave a Reply

Your email address will not be published.