Published on

Ember.js: Build a Markdown component with ShowdownJs

With the help of ShowdownJs and HighlightJs, you can easily build a Markdown component with syntax highlighting.

ShowdownJs is an easy-to-use Markdown to HTML converter, it can be used in both client-side (browser) or server-side (with nodejs).

HighlightJs is an JavaScript library for syntax highlighting on the web. It supports 189 languages and 94 styles.

Create a MarkdownView component

Install the ShowdownJs library from npm or yarn:

# Using npm
$ npm install showdown --save-dev

# Using yarn
$ yarn add showdown --dev

Now you need create a <MarkdownView /> component, and use ShowdownJs to convert the Markdown into HTML:

ember g component markdown-view -gc
// app/components/markdown-view.js

import Component from '@glimmer/component';
import { htmlSafe } from '@ember/template';
import showdown from 'showdown';

const converter = new showdown.Converter()

export default class MarkdownViewComponent extends Component {
  get html() {
    return htmlSafe(converte.makeHtml(this.args.markdown))
  }
}
{{! app/components/markdown-view.hbs }}

{{html}}

You can easily pass in the Markdown from one of your routes.

// app/routes/post.js
import Route from '@ember/routing/route';

export default class PostRoute extends Route {
  model() {
    return '# Hello Ember!';
  }
}
// templates/posts.hbs

<MarkdownView @markdown={{@model}} />

Add syntax highlighting using HighlightJs (Optional)

Let’s add syntax highlighting to the <MarkdownView /> component using HighlightJs.

Install the HighlightJs library from npm or yarn:

# Using npm
$ npm install highlight.js --save-dev

# Using yarn
$ yarn add highlight.js --dev

Now you need update the <MarkdownView /> component:

// app/components/markdown-view.js

import Component from '@glimmer/component';
import { htmlSafe } from '@ember/template';
import showdown from 'showdown';
import hljs from 'highlight.js';

showdown.extension('highlight', function () {
  return [{
    type: "output",
    filter: function (text) {
      var left = "<pre><code\\b[^>]*>",
          right = "</code></pre>",
          flags = "g";

      var replacement = function (wholeMatch, match, left, right) {
        var lang = (left.match(/class="([^ "]+)/) || [])[1];
        left = left.slice(0, 18) + 'hljs ' + left.slice(18);

        if (lang && hljs.getLanguage(lang)) {
          return left + hljs.highlight(lang, match).value + right;
  } else {
          return wholeMatch;
  }
      };

      return showdown.helper.replaceRecursiveRegExp(text, replacement, left, right, flags);
    }
  }];
});

const converter = new showdown.Converter({extensions: ['highlight']})

export default class MarkdownViewComponent extends Component {
  get html() {
    return htmlSafe(converter.makeHtml(this.args.markdown))
  }
}

Finally, you need to import a Highlight.js theme. You can do that by importing the CSS file from node_modules in your ember-cli-build.js file with app.import:

// ember-cli-build.js

// ..

module.exports = function(defaults) {
  // ...

  app.import('node_modules/highlight.js/styles/default.css');

  return app.toTree();
};

You can found here a list of all Highlight.js themes and languages.

Conclusion

In this tutorial we have seen how to build a Markdown component with syntax highlighting using ShowdownJs and HighlightJs.

See also