Embedding Code Into Medium
How to embed code on Medium, and analysis of the options available to you.
TL;DR
Medium doesn’t have native support for syntax hilighting for code snippets. Fortunately, you can embed
other services that support it into Medium articles. Which UI is best?
If you’d like to jump ahead to any sections, or need to quickly access them later, here’s the low down:
1. What We’re Looking For
2. Feature Overview
3. Comparison
4. Overview
Foreword 💃
Medium doesn’t have powerful, native support for embedding code, or anything for that matter. Whether it is a Tweet, Instagram video, code, or something else, Medium relies on a third party service called Embedly.
That sucks, right? Except it doesn’t. Medium can focus on what makes Medium awesome, and leave the nitty gritty details of embedding to the experts at Embedly.
Since Medium utilizes Embedly, any provider that Embedly supports is automatically supported by Medium. Embedly supports over 700 different content providers. All Embedly does is embed an iframe
HTML element into the Medium post. The content provider only needs to follow some simple guidelines. If you have an idea for a cool embed, it is relatively straightforward to become an Embedly provider.
Here are some popular supported providers you might know.
Code
- Github Gists
- Codepen.io
- JSFiddle
Video
- YouTube
- Vimeo
- Hulu
Image
- Dribbble
- Imgur
- Flickr
Media
- Scribd
- Prezi
- Storify
- SlideShare
You can view the full list of supported providers on Embedly’s website, and read the FAQ for embeds on Medium’s official documentation.
Let’s take a look at some options we have to embed code, in context of how you might practically want to do so. In this article, we’ll explore the three options suggested by Medium in their official documentation.
- Github Gists
- Codepen.io
- JSFiddle
What We’re Looking For
Here is what I’m looking for in my ideal embed:
Clean UI for large and small embeds
We don’t want to embed a clunky, ugly code block that distracts, but a sleek and sexy UI that enhanced the viewing experience. For large code blocks, this isn’t an issue. However, often many smaller 4–5 line embeds are used in sequence to explain and demonstrate small bits of code. If there is a lot of UI boilerplate around the embed, this can look clunky.
Code should look good on Mobile and desktop. For example, I prefer my code blocks to be horizontally scrollable if the screen width is too small to fit, instead of automatically wrapping.
Syntax highlighting for common languages
Syntax highlighting is a must for even the most simple of code blocks. Especially since examples to explain a general concept may use a language that not everyone is familiar with. Syntax highlighting improves readability and understandability. All the other ‘-ility’, too.
Easy to update and organize disparate and related code
I go through code examples I provide with a fine tooth comb, and often copy and paste them from a program that is actually being executed. Still, a typo or incidental bug here or there is likely to slip in. Plus, over time my opinions may change (or be completely wrong!) and code will be updated to reflect that.
Keeping all of my code samples well organized and easy to edit is a must.
Nice To Have
Able to embed a subset of lines from a single file
The ability to embed lines 15–20 from a single source will make my life easier. I won’t have to manage 30 different code bits for one article, updating each one if something should change.
It also improves the user experience because it is clear when an extracted example comes from a larger context. Which… improves readability and understandability. All the other ‘-ility’, too.
Customizable color scheme
Sometimes code looks good on ‘my machine’ because of the settings for my IDE. It might be nice to change the color scheme based on if the user is browsing in Dark Mode
, too.
These are all preference based wants, and are what we’ll be using to evaluate each method of embedding code.
Feature Overview
Services like `codepen.io` offer a premium version that may offer more powerful features. For our purposes, we only care about free versions. Although some of the premium features are pretty spicy, so we may take a look at those in another article. Here we’ll take a look at the websites for the services themselves, ignoring how they render on Medium.
Github Gists
Style
Light theme with standard highlighting you’d see on Github.
Languages
GitHub gists are powered by Code Mirror which supports over 100 languages.
- HTML (Haml, Markdown, Slim, Pug)
- CSS (Less, SCSS, Sass, Stylus, PostCSS)
- JS (Babel, Typescript, Coffeescript, Livescript)
Organization
Gists are the most basic tool out of the three main ones. There isn’t a native way to organize your gists, they all just show up in one collection, sortable by ‘created’ or ‘updated’ date. Fortunately, there are some external tools like cacher.io that gives you powerful tools to organize and manage your gists.
Thoughts
Since gists are just Git repositories, they come with all the nice features that you’d expect: revision history, tooling through GitHub’s API, and Starring
The UI is clean and easy to use, as expected from a tool that isn’t trying to do a lot. Notice how there is no execution of code, only the raw source is embeddable.
The documentation around Gists is a little scattered. Here is some deprecated documentation that does a good job giving an overview of gists. The current official ‘documentation’ doesn’t say much and is missing a lot of information, but feel free to take a look. Personally, I’d just read through the gists API documentation to learn more.
Codepen.io
Style
Dark theme with pastel colored syntax highlighting, one customizable theme for free users. Has a side-by-side view of code and executed result.
Languages
- HTML (Haml, Markdown, Slim, Pug)
- CSS (Less, SCSS, Sass, Stylus, PostCSS)
- JS (Babel, Typescript, Coffeescript, Livescript)
Organization
- Full blown ‘Projects’, with a 1 project limit for free users
- Group different pens and projects into ‘Collections’
Other
- Templates to start new code pens with. There are community provided templates, and you can create your own.
- Support for external scripts and linking to other ‘pens’
- Premium features
Thoughts
The organization features are relatively powerful, and are enough to keep Pens decently organized. There is no versioning system, so you can’t see previous versions of your snippet.
The UX feels a little clunky, and navigating isn’t immediately obvious. With a little exploring, the UI becomes reasonably intuitive, and the official docs are well fleshed out.
JSFiddle
Style
- Dark theme with slightly higher color contrast than default Codepen.io dark theme.
- Initially renders with result of code, but user can choose to show
JS
code.
Languages
- HTML (Haml)
- CSS (SCSS, Sass)
- JS (Babel + JSX, Typescript, Coffeescript, React, Vue, and more)
- JS Frameworks (Angular, React, Vue, jQuery, and more)
Organization
- Group different pens and projects into ‘Collections’
- You can
Save/Update
fiddles, adding a new version number. OrFork
Fiddle, splitting the existing Fiddle into a new one, starting at version 0.
Other
- Default boilerplate to start new Fiddles with.
- Support for external resource like CSS or JS
- Premium features, including categorizing aka ‘grouping’ Fiddles
Thoughts
The free version doesn’t offer a way to group your Fiddles. But, it’s nice that you can go back to previous versions of your code, although accessing them is a little wonky. You need to manually change the version number in the url to the version number you want.
The UI of the main website isn’t super obvious, so be sure to check out the official JSFiddle Docs.
The UX was a little wonky at times, partially due to the simple non-obvious UI, but also some things didn’t feel like they were working. In order to update the Title
and Description
of my fiddle, I had to Fork
it each time. Also, accessing previous versions is wonky, as mentioned above.
Comparison
Feature Comparison
Let’s briefly analyze the benefits of each provider and when you may want to choose one over the other, not yet considering how the embeds will actually render.
Displaying code
Gists supports all the languages you’ll probably need, and is the most convenient. Gists are connected right to your Git account, and with cacher.io you can powerfully organize your gists. If you only need to show a single file or are okay with embedding each file sequentially, Github gists is your best bet.
JSFiddle and Codepen are nice fallbacks if you really want to show a set of connected HTML
, CSS
, and Javascript
files in one block, accessed through multiple tabs. Between the two, I’d prefer using Codepen, as the organizational features feel more robust. Keep in mind JSFiddle supports a greater set of languages and javascript frameworks, which may be valuable depending on your use case.
Executing code
Medium doesn’t let you execute code that modifies the DOM of the actual Medium site, for security reasons. Since the embeds are just inline <iframe>
elements, they get their own separate execution environments.
Github gists doesn’t support executing code, so your only options are JSFiddle or Codepen. Again, I’d prefer Codepen unless I needed to use a specific language or framework only supported by JSFiddle.
Note: Some of the services offer options for customizing the embeds UI. The customization features aren’t available on Medium, since just the URL is used to embed rather than the full embed script.
Embed Comparison
To evaluate each provider, we’ll be using the code used inanother article I’ve written called What is Testing?. The feature wishlist we defined in What We’re Looking For errs toward just displaying code and not executing it. Similarly,
Remember, to embed code just put the link to the resource. Don’t use any provided ‘Embed’ <script>
tags.
Large Blocks
Let’s render the full gist for each provider.
Native
// what_is_testing
/**
* Calculates the number of the specified pokemon caught given a map representing the current Pokedex state.
*
* @param {{pokemon: string, count: number}} pokedexState the sample Pokedex state
* @param {string} pokemonToCount the list of Pokemon to include in the total count
* @returns {number} the total specified Pokemon caught
*/
let calculateTotalSpecifiedPokemonCaught = ( pokedexState, ...pokemonToCount ) => {
let totalPokemonCaught = 0
for ( let index = 0; index < pokemonToCount.length; index++ ) {
let currentPokemon = pokemonToCount[ index ]
totalPokemonCaught += pokedexState[ currentPokemon ]
}
return totalPokemonCaught
}
/**
* @param {string} testID a description to match this result to the executed function
* @param expected expected result of the test function
* @param actual actual result of the test function
*/
let checkResults = (testID, expected, actual) => {
if ( expected === actual ) {
console.log(`SUCCESS test '${testID}'`)
}
else {
// using ES6 template literals to format output string with expected data
console.log( `FAILED test '${testID}' -- expected ${expected} but got ${actual}` )
}
}
//// sample test data
let samplePokedexState = {
'Pikachu': 4,
'JigglyPuff': 2,
'MewTwo': 1,
'Bulbasaur': 1
}
let sampleEmptyPokedexState = {}
//// test calls
let result;
// empty data parameters
result = calculateTotalSpecifiedPokemonCaught( sampleEmptyPokedexState )
checkResults( 'empty data', 0, result )
// non-empty Pokedex, looking for Pokemon that exist within the map
result = calculateTotalSpecifiedPokemonCaught( samplePokedexState, 'Pikachu', 'Bulbasaur' )
checkResults( 'existing Pokemon', 5, result )
// non-empty Pokedex, looking for Pokemon that don't exist within the map
result = calculateTotalSpecifiedPokemonCaught( samplePokedexState, 'Vulpix' )
checkResults( 'missing Pokemon', 0, result )
// non-empty Pokedex, looking for some Pokemon that don't exist within the map, and some that do
result = calculateTotalSpecifiedPokemonCaught( samplePokedexState, 'Vulpix', 'Pikachu' )
checkResults( 'existing and missing Pokemon', 4, result )
// SUCCESS test 'empty data'
// SUCCESS test 'existing Pokemon'
// FAILED test 'missing Pokemon' -- expected 0 but got NaN
// FAILED test 'existing and missing Pokemon' -- expected 4 but got NaN
Github Gists
Codepen.io
JSFiddle
Thoughts
- Native doesn’t really wrap well and you can easily get lost in long bits of code.
- Gists shows line numbers, makes it easy to reference a line in the article.
- Gists has a clean simple UI, the lightmode can be a bit jarring when browsing via mobile dark mode.
- Gists’ simple UI looks like it ‘fits’ in the page and doesn’t immediately scream
<iframe>
- Codepen dark UI is nice, but no line numbers.
- Codepen and Gists links back to the original source, so you can easily ‘Star’ or otherwise save and modify each snippet. Gists provides a direct link to the raw source. On mobile, it seems you need to long press to navigate to
the source, as it is an external link.
Small Blocks
For inline code, I don’t usually care about syntax highlighting, so the native Medium code embed support works fine.
Typically when I reference smaller code blocks in my articles, it is in reference to a larger document. It would be nice to be able to provide line numbers that are contextual to where the small sub-section is within the larger document.
None of our current tools offer support for embedding sub-sections of code frome a single larger snippet. It’s all or nothing.
For now, let’s see how each provider renders a small context-free snippet. We’ll think about our options for embedding more context-aware sub-section snippets after. Here are two small snippets, one with vanilla javascript and the other using Typescript.
Native
// sample enum
enum TestIDEnum {
NOTE_OPTION_FAVORITE = 'note-option-favorite',
NOTE_OPTION_REMOVE_CATEGORY = 'note-option-remove-category',
NOTE_OPTION_RESTORE_FROM_TRASH = 'note-option-restore-from-trash',
NOTE_OPTION_TRASH = 'note-option-trash',
}
// simple 'map' using javascript object notation
let samplePokedexState = {
'Pikachu': 4,
'JigglyPuff': 2,
'MewTwo': 1,
'Bulbasaur': 1
}
Github Gists
Codepen.io
JSFiddle
Thoughts
Woe is me. It is truly a crying shame that there isn’t native support for embedding sub-sections of a single file. My thoughts for small blocks generally mirrors my thoughts for larger blocks.
For small blocks, especially if they are consecutive blocks, Github gists gets a double gold star since the UI integrates visually better with the page. If the block is a sub-section of a larger document, the fact that the line numbers start at ‘1’ for every block makes it feel a bit visually awkward. At least it makes it easier to reference code by line number in the article, but it doesn’t feel “right”.
There is something to be said about the simplicity of the native code blocks, though. If you won’t be needing syntax highlighting, then for small snippets I don’t actually mind the UI. It is better than having all of the noisy additonal UX elements of the embeds, and works well on mobile. Just make sure your code doesn’t wrap (don’t forget about mobile!), or it will appear a bit wonky.
Overview
Each different service has a different approach to tackling similar problems. Let me know in the comments below what you use!