Lachlan's avatar@lachlanjc/notebook

Tech explainer: Next.js, MDX, Theme UI

I’ve recently built a number of sites using a new tech stack, where pages are written in Markdown with embedded React components & theme-able (e.g. dark/light modes) styling.

I’ve written this explainer for the React user who’s a beginner to the world of CSS-in-JS, MDX, etc.

Note: the following is extracted from my tutorial on building a hackathon website.

Three pillars of our tech stack

  1. We’re using the Next.js framework. React is just a library you can run on a webpage—Next makes it easy to build a full, multi-page site (either with dynamic server components or a static site, like these are), handling asset bundling, routing, etc.
    • Next is wildly easy to get started with, & once you’ve got a site, you can add a new page just by making a file at pages/about.mdx with some text in it, & you now have a high-performance static page at /about on your site. This is magical.
  2. We’re using MDX to write content. It’s Markdown with superpowers: all the normal Markdown stuff works, but then you can also embed React components inside your text (great for styling, adding forms, etc!), or include other MDX files as React components in other MDX files. It makes authoring pages super easy, because suddenly you only have to write code if you want custom styling on your page, not just to get text on the screen.
  3. Theme UI handles styling, with Emotion underneath & Rebass on top. Breaking this down: Emotion handles dynamically generating the actual CSS based on which components are on each page. Theme UI is the library that lets you use themes (e.g. dark & light modes) & provides a really nice API for styling React/MDX components. Rebass is a library on top with pre-made Theme UI components, for using CSS Flexbox, or adding buttons or form elements with basic styling applied.

The site is then hosted on Netlify, because it’s free, easy to set up, automatically deploys whenever you push to GitHub, & just works (most of the time).

Looking at a codebase

Check out the Hack Pennsylvania recap site codebase, open source & under the MIT License:

The two important folders are pages & components—that’s where you’ll spend the vast majority of your time editing the site. Pages are written in MDX (or JSX), components in JSX (React components).


How styling works is a bit complex, but once you wrap your head around the system, it’s incredibly fast to work with.

It starts with a theme. The theme keeps all the primary “components” of your design—all the colors & fonts, but also the amounts of spacing (margin/padding in CSS), the font sizes used, the box-shadows used, etc, all in one place. By not having colors & font sizes & friends all spread out through your codebase, you can super easily modify the look of your whole site just by changing the theme, & you’ll also have fantastic consistency in your design, because you won’t have a random colors used in just one place or the like.

  • Themes also open up having a light mode & a dark mode—or even more craziness :) The default colors set is the light mode, then when the dark mode is in use, the colors dynamically change to what you’ve defined in the theme.
  • You should almost never find yourself manually setting a font size or color on pages/components of the site—keep everything in your theme. Keep reading to see how to use values defined in your theme…

You won’t be writing direct CSS anywhere on the site. You’ll instead see sx={{ on the components & on the pages. A quick guide to what goes inside the sx prop:

  • When you write fontSize: 3 inside sx={{ … }}, you won’t get the CSS font-size: 3px;. Instead, Theme UI will look up the third font size value in your theme.
  • When you pass an array for a property like fontSize, you’re generating CSS Media Queries for responsive styling. fontSize: [3, 4, 5] means that on phones & screens larger than phones, the element will use the theme’s font size #3, then on tablets, theme value #4, then on laptops & larger, theme value #5. As you can see, for very little code, you can make a site that’s optimized for all screen sizes.
  • You might notice weird properties that don’t correspond to standard CSS properties, like my, mr, px, etc. These are for margin & padding, using the theme space scale values just like how font size works. mt means margin-top, mb = margin-bottom, then my is margin on the Y axis, so both top & bottom (full set: my mx my mr mb ml). The same goes for padding, its properties beginning with p (full set: py px pt pr pb pl).
  • bg sets the background-color to one of the colors in your theme. color sets the text color similarly. The superpower here is that if you enable dark mode or another theme, the colors dynamically change to that theme, as defined in your theme file.
  • This is all processed by Theme UI, so check our their website for more details.

I wrote a bit more about how styling is used at a component level over here about the Hack Pennsylvania site.