loading...

Using Basecamp's Trix Editor in React ( Shopify Polaris )

zubairmohsin33 profile image Zubair Mohsin ・3 min read

This post was originally published on Medium. Link

The Need

I develop Shopify Apps as a Freelancer and Shopify has offered their own UI toolkit called Polaris which is highly recommended for building apps interfaces.
They offer React Components and also HTML/CSS version of components. Sadly, there is no Rich Text Editor component in the toolkit as of now. Although, it's under consideration.

Research

I did some research and found two options:

  • TinyMCE
  • Trix Editor  

TinyMCE is feature rich and offers a lot, But I needed a simple one so I decided to go with Trix.

Getting Started:

Pull in Trix using npm:

npm install trix
Enter fullscreen mode Exit fullscreen mode

Next, let's create a component named wysiwyg.jsx and use it in App component.
App.js

import React, { Component } from "react";
import ReactDOM from "react-dom";
import {
    AppProvider,
    Page,
    Card,
    Layout,
} from "@shopify/polaris";
import Wysiwyg from "./components/wysiwyg";

export default class App extends React.Component {

  state = {
    content: ""
  }

  render(){
    return(
      <AppProvider apiKey={apiKey} shopOrigin={shopOrigin} forceRedirect={true}>
        <Page>
          <Layout>
            <Card>
                <Wysiwyg />
            </Card>
          </Layout>
         </Page>
      </AppProvider>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

wysiwyg.jsx

import React, { Component } from "react";
import Trix from "trix";

class Wysiwyg extends React.Component {

    render() {
        return (
            <div>
                <input
                    type="hidden"
                    id="trix"
                />
                <trix-editor input="trix" />
            </div>
        );
    }
}

export default Wysiwyg;
Enter fullscreen mode Exit fullscreen mode

Trix editor stores its a content in a hidden element. ID property on that hidden element and input property on trix-editor must be same.

At this point you will see Trix working, if styles are not there, you can pull the stylesheet from CDN, or put a link tag. I am using laravel-mixso I imported the stylesheet in my app.scss like below:

@import "~trix/dist/trix.css";
Enter fullscreen mode Exit fullscreen mode

Populating the stored content 😍

We can pass the data to component with props.

<Wysiwyg value={this.state.content} />
Enter fullscreen mode Exit fullscreen mode

and accepting this prop in the component as below:

<input type="hidden" id="trix" value={this.props.value} />
Enter fullscreen mode Exit fullscreen mode

Updating the STATE 🤔

This is a little bit tricky. State is in the parent component and we need to tell the parent component that content of the editor is being changed.

Trix editor raises an event called trix-change 🔗 . We can listen to this event and raise our own custom event.

Since trix-editor is in the DOM, we need refs to access it.

wysiwyg.jsx

import React, { Component } from "react";
import Trix from "trix";

class Wysiwyg extends React.Component {
    constructor(props) {
        super(props);
        this.trixInput = React.createRef();
    }

    componentDidMount() {
        this.trixInput.current.addEventListener("trix-change", event => {
            console.log("trix change event fired");
            this.props.onChange(event.target.innerHTML); //calling custom event
        });
    }

    render() {
        return (
            <div>
                <input type="hidden" id="trix" value={this.props.value} />
                <trix-editor input="trix" ref={this.trixInput} />
            </div>
        );
    }
}

export default Wysiwyg;
Enter fullscreen mode Exit fullscreen mode

Event handler on the parent component, via props as below:
App.js

import React, { Component } from "react";
import ReactDOM from "react-dom";
import {
    AppProvider,
    Page,
    Card,
    Layout,
} from "@shopify/polaris";
import Wysiwyg from "./components/wysiwyg";

export default class App extends React.Component {

  state = {
    content: ""
  }

  render(){
    return(
      <AppProvider apiKey={apiKey} shopOrigin={shopOrigin} forceRedirect={true}>
        <Page>
          <Layout>
            <Card>
                <Wysiwyg onChange={this.handleContentChange} />
            </Card>
          </Layout>
         </Page>
      </AppProvider>
    );
  }


  handleContentChange = (content) => {
    this.setState({content : content});
  };
}
Enter fullscreen mode Exit fullscreen mode

If you need multiple wysiwyg on same page, you can play around with passing props for id etc.

So, this is how you can use Trix Rich Text Editor in React and make it a reusable component.

This approach is heavily inspired by Laracast’s episode on Wysiwyg. here.

Happy coding 👨🏽‍💻

Discussion

pic
Editor guide