This post offers a peek at the technology behind this website. In the spirit of remixing, I’m hoping this provokes ideas for using ObservableHQ in unexpected ways.
Putting Observable Notebooks in Markdown
I recently learned of Chris Biscardi’s gatsby-mdx
library, which enables the usage of React components inside Markdown (.md
) files. With this library, we are not limited to using vanilla HTML and CSS to write my content.
I built this blog with Gatsby.js instead of a static site generator powered by a server-side language because I wanted to have flexibility to include interactive capabilities. I previously thought I would have to write entirely new React pages to do so, so I was excited to add gatsby-mdx
to my code. However, I lacked a specific React-powered use case. Today, one appeared!
Last year, I published several data visualization tutorials on the ObservableHQ platform. However, I hadn’t figured out how to host that content on my own site without resorting to using iframes
. While that approach technically works, I wouldn’t have control over how the imported content was styled. There had to be a better way.
Today, I saw Chris Knox’s post about building a bar-chart race graph in Observable. He was able to import his work into a news article for the New Zealand Herald using npm
directly. I decided to put his approach into a React component, and try it on one of my notebooks. As a guinea pig, I selected a walkthrough I’d made for a Coding Train video about using p5.js
to recreate one of Dave’s (bees and bombs) animations.
This is what the React wrapper component for the notebook looks like:
// breathing-cube-observablehq.jsx
import React, { Component } from 'react';
import { Runtime, Inspector } from '@observablehq/runtime';
// Right click the "export to code" link in the notebook's sharing options
// yarn install https://api.observablehq.com/@hydrosquall/breathing-cube-in-p5-js.tgz
import notebook from 'breathing-cube-in-p5-js';
const mountId = 'observable-mount';
class ImportedNotebook extends Component {
componentDidMount() {
const root = document.getElementById(
mountId
);
// Via
// https://observablehq.com/@observablehq/downloading-and-embedding-notebooks
Runtime.load(
notebook,
Inspector.into(root)
);
}
render() {
return (<div id={mountId} style={{ textAlign: 'center' }}> </div>);
}
}
export default ImportedNotebook;
Then, I included the following in my .mdx
file for this post.
import ImportedNotebook from '../../src/components/breathing-cube-observable';
# ... the markdown part of my blog post
<ImportedNotebook/>
# ... conclusion to blog post
That’s it! With just a few lines, the full catalog of ObservableHQ cells and functions are available for usage inside any markdown/MDX files. Note that it’ not just the visual output cells that work - the cells with “knobs” for toggling colors and bar width are all functional.
Aside: The mdx
syntax highlighting for this code block works with the help of the recently released gatsby-remark-vscode.
Library Summary
To recap what each acronym is contributing to this post
gatsby
converts a folder of JSX files into a JS and HTML blog suitable for hosting as a static site.JSX
is the templating language used byReact.js
, which lets you mix Javascript and HTML.Markdown
(MD) converts a human readable markup language to HTML. Markdown works inside many tools used by developers, including Github, JIRA, and Slack.MDX
is a superset of Markdown, which acceptsReact.js
components in addition to standard HTML.ObservableHQ
is an online Javascript notebook for running and sharing reactive code snippets onlinep5.js
is a javascript library for creative visual codingd3.js
can do all sorts of things for data visualization, but here it is just doing a little bit of math.
Everything between the horizontal lines is from the notebook.
Wrap-up
There are at 2 least pieces of this import that that did not go as smoothly as I had hoped. I think these are reasons to view this content on ObservableHQ instead of using the import method.
- Viewing and editing the source code for each Observable cell isn’t supported.
- Some of the CSS for my blog conflicts with the notebook styling, some of the cells are formatted strangely.
Both of these issues can be overcome by writing a React.js
wrapper that is more selective about which cells to import, instead of importing every single cell. In future posts, I will curate the imported cells more carefully. I’m leaving this post as-is to show how a variety of cell types perform when imported without special treatment.
Let me know if you end up trying this workflow!