Let's build a Markdown component

By leveraging Ember Auto Import, we can make our own Markdown component with syntax highlighting using MarkdownIt and Highlight.js.

Summary

From a brand new app, we start by installing the ember-auto-import addon

ember install ember-auto-import

Next, install the MarkdownIt library directly from npm:

yarn add -D markdown-it

Now we can create a new <Markdown /> component, and use MarkdownIt to render some HTML:

// markdown/component.js
import Component from '@ember/component';
import MarkdownIt from 'markdown-it';
import { computed } from '@ember/object';
import { htmlSafe } from '@ember/string';

const md = new MarkdownIt();

export default Component.extend({

  source: 'Hello, *markdown*!',

  html: computed('source', function() {
    return htmlSafe(md.render(this.source));
  })

});
{{! markdown/template.hbs }}
{{html}}

Using angle bracket syntax and the @ sign, we can easily pass in new source content from our Application template. (We'll also install dedent to make our lives a little easier).

// application/controller.js
import Controller from '@ember/controller';
import dedent from 'dedent';

export default Controller.extend({

  blogPost: dedent`
    # Quick start

    This guide will teach you how to build a simple app using Ember from scratch.

    We'll cover these steps:

      1. Installing Ember.
      2. Creating a new application.
      3. Defining a route.
      4. Writing a UI component.
      5. Building your app to be deployed to production.
  `

});
{{! application/template.hbs}}

<Markdown @source={{blogPost}} />

Looking good!

To add syntax highlighting, we're going to use Highlight.js. Let's install it with Yarn:

yarn add -D highlight.js

Now we can add a highlight function to our MarkdownIt instance:

import Component from '@ember/component';
import MarkdownIt form 'markdown-it';
import hljs from 'highlight.js';
import { computed } from '@ember/object';
import { htmlSafe } from '@ember/string';

const md = new MarkdownIt({
  highlight(code, lang) {
    let highlihgtedCode = code;

    if (hljs.getLanguage(lang)) {
      highlightedCode = hljs.highlight(lang, code).value;
    }

    return `<pre class='hljs'><code>${higlightedCode}</code></pre>`;
  }
});

export default Component.extend({

  classNames: 'Markdown',
  source: 'Hello, *markdown*!',

  html: computed('source', function() {
    return htmlSafe(md.render(this.source));
  })

});

Finally, we need to import a Highlight.js theme. We can do that by importing the CSS file directly from node_modules in our ember-cli-build.js file:

app.import('node_modules/highlight.js/styles/atom-one-dark.css');

And with that, we have a <Markdown /> component, complete with syntax highlighting using a theme of our choosing!

If we don't want to include all of Highlight.js's languages into our bundle, we can whitelist the ones we want:

- import hljs from 'highlight.js';
+ import hljs from 'highlight.js/lib/highlight';
+ import javascript from 'highlight.js/lib/languages/javascript';
+ import css from 'highlight.js/lib/languages/css';
+ import handlebars from 'highlight.js/lib/languages/handlebars';
+ import htmlbars from 'highlight.js/lib/languages/htmlbars';
+ import json from 'highlight.js/lib/languages/json';
+ import xml from 'highlight.js/lib/languages/xml';
+ import diff from 'highlight.js/lib/languages/diff';

+ hljs.registerLanguage('javascript', javascript);
+ hljs.registerLanguage('css', css);
+ hljs.registerLanguage('handlebars', handlebars);
+ hljs.registerLanguage('htmlbars', htmlbars);
+ hljs.registerLanguage('json', json);
+ hljs.registerLanguage('xml', xml);
+ hljs.registerLanguage('diff', diff);

View the full diff from the video here.

👋 Hey there, Ember dev!

We hope you enjoyed this free video 🙂

If you like it and want to keep learning with us, we've written a free 6-lesson email course about the fundamental patterns of modern component design in Ember.

To get the first lesson now, enter your best email address below:

You can also check out more details about the course by clicking here.

Questions?

Send us a tweet:

Or ask us in Inside EmberMap, our private Slack workspace for subscribers.