DANIEL MARIN

Rendering Showcase

A reference page exercising every Markdown, MDX, code, and math feature the blog supports, with the expected output described for each

7 min

This page exercises every construct the blog pipeline supports. Each section states the feature under test and the output that constitutes correct rendering, so that a regression in a plugin, a style rule, or a component override is visible on inspection.

The pipeline consists of @next/mdx with the remark and rehype plugins listed below, and typography supplied by the Tailwind prose classes as configured in BlogContent.tsx.

PluginStageFunction
remark-frontmatterremarkParses the YAML block so it can be removed from the tree
remark-mathremarkRecognizes $...$ and $$...$$ delimiters
remark-gfmremarkTables, task lists, strikethrough, footnotes
rehype-highlightrehypeSyntax highlighting by language
rehype-highlight-code-linesrehypeLine numbers within code blocks
rehype-katexrehypeRenders math to HTML

1. Headings

Second-level headings carry a bottom border and increased top margin. Third-level headings are smaller and unruled. Fourth-level headings receive no explicit override and fall back to the prose defaults.

1.1 A third-level heading

Body text at the third level is styled identically to body text elsewhere; only the heading differs.

A fourth-level heading

Correct rendering shows four distinct sizes with decreasing weight and no border below the third and fourth levels.

2. Inline text

Text may be bold, italic, bold and italic, struck through, or set as inline code. Inline code is rendered on a muted background with rounded corners and no surrounding backticks; visible backtick characters indicate that the prose-code pseudo-element overrides have regressed.

Links take the prose defaults, as in the Next.js MDX documentation. Link styling is only observable inline, so it is tested in a sentence rather than in isolation.

A single newline within a paragraph does not produce a line break. Two trailing spaces do produce one, as at the end of the previous line.

3. Lists

Unordered lists nest to three levels:

  • First-level item
  • Item containing inline code
    • Second level
    • Second level, sibling
      • Third level
  • First level, resumed

Ordered lists nest and renumber independently at each level:

  1. First step
  2. Second step
    1. Substep
    2. Substep, sibling
  3. Third step

Task lists are provided by remark-gfm. Correct rendering shows a checkbox with no list marker beside it:

  • Parse frontmatter and remove it from the output
  • Render block and inline mathematics
  • Provide a Callout component
  • Add anchor links to headings

4. Blockquotes

A blockquote is rendered with a left border and italic text, and should remain legible when the content is long enough to wrap across several lines.

Consecutive paragraphs are permitted, and inline formatting is preserved within them. No quotation marks are inserted; if they appear, the prose blockquote pseudo-elements have not been cleared.

5. Code blocks

Code blocks are wrapped by the CodeBlock component, which adds a copy button on hover, and line numbers are supplied by rehype-highlight-code-lines. Highlighting is selected by the language tag on the opening fence.

import numpy as np

def neuron(inputs, weights, bias):
    """
    Single-neuron computation.
    """
    weighted_sum = np.dot(inputs, weights) + bias
    return sigmoid(weighted_sum)

def sigmoid(x):
    """Sigmoid activation function."""
    return 1 / (1 + np.exp(-x))
type Post = {
  slug: string;
  title: string;
  date: string;
  draft?: boolean;
};

export function published(posts: Post[]): Post[] {
  return posts
    .filter((post) => !post.draft)
    .sort((a, b) => b.date.localeCompare(a.date));
}
npm run generate-mdx   # regenerate content/blog imports
npm run dev            # runs generate-mdx first
{
  "title": "Rendering Showcase",
  "date": "2024-01-20",
  "draft": false
}

A line wider than the content column determines whether the block scrolls horizontally or wraps. Correct behavior is a horizontal scrollbar confined to the block, with no horizontal scrolling of the page:

const result = await fetch('https://example.com/api/posts?limit=50&offset=0&include=author,tags&sort=-publishedAt').then((response) => response.json());

A fence with no language is rendered without highlighting and retains both the line numbers and the copy button:

$ curl -s https://example.com/health
ok

6. Mathematics

Inline mathematics is set on the surrounding baseline and must not disturb the line spacing. The mass-energy relation E=mc2E = mc^2 and the taller expression i=1nwixi\sum_{i=1}^{n} w_i x_i both appear in this paragraph for that reason.

Display mathematics is centered in its own block:

y=f(i=1nwixi+b)y = f\left(\sum_{i=1}^{n} w_i x_i + b\right)

where xix_i are the inputs, wiw_i the weights, bb the bias, and ff the activation function. Definitions of this kind are set as running text rather than as a list, since the terms are short.

Propagation between layers, with the output of one layer forming the input to the next:

a(l)=f(W(l)a(l1)+b(l))a^{(l)} = f\left(W^{(l)} a^{(l-1)} + b^{(l)}\right)

The chain rule applied to the loss with respect to a single weight:

Lwij(l)=Laj(l)aj(l)zj(l)zj(l)wij(l)\frac{\partial L}{\partial w_{ij}^{(l)}} = \frac{\partial L}{\partial a_j^{(l)}} \cdot \frac{\partial a_j^{(l)}}{\partial z_j^{(l)}} \cdot \frac{\partial z_j^{(l)}}{\partial w_{ij}^{(l)}}

Multi-line alignment and matrix environments are the constructs most likely to fail in a KaTeX configuration, and are tested here:

z(l)=W(l)a(l1)+b(l)a(l)=f(z(l))y^=a(L)\begin{aligned} z^{(l)} &= W^{(l)} a^{(l-1)} + b^{(l)} \\ a^{(l)} &= f\left(z^{(l)}\right) \\ \hat{y} &= a^{(L)} \end{aligned} W=[w11w12w13w21w22w23]W = \begin{bmatrix} w_{11} & w_{12} & w_{13} \\ w_{21} & w_{22} & w_{23} \end{bmatrix}

Equation numbering is available through \tag, which renders right-aligned within the display block:

θL=1Ni=1Nθ(fθ(xi),yi)(6.1)\nabla_\theta L = \frac{1}{N}\sum_{i=1}^{N} \nabla_\theta \ell\left(f_\theta(x_i), y_i\right) \tag{6.1}

Numbered equations may then be referred to by number, as (6.1) is here.

7. Tables

Tables are provided by remark-gfm. The table in the introduction uses default alignment; the one below sets alignment per column, with the numeric column right-aligned.

FeatureStatusLines of config
Syntax highlightingdone3
Mathematicsdone2
Calloutspending0

8. Horizontal rules


A horizontal rule separates content without introducing a level of hierarchy, and is distinguishable from the border beneath a second-level heading by its position and full width.

9. MDX components

Because these files are compiled as MDX, JSX may be written inline. This is the mechanism for any content Markdown cannot express.

Note
This element is raw JSX with Tailwind classes, written directly in the MDX source. The not-prose class excludes it from the surrounding typography styles.

Multi-line children of a JSX element are reparsed as Markdown and wrapped in a paragraph. A <p> element with children on separate lines therefore produces a paragraph nested inside a paragraph, which is invalid HTML and raises a hydration error at runtime. Use <div> for such containers, as above.

9.1 Registered components

Components registered in mdx-components.tsx are available in MDX without an import. The file currently overrides pre to supply the copy button on code blocks and registers the NeuralManifold component below.

The element above is written as <NeuralManifold size="sm" /> in the MDX source, inside a centering wrapper and with no import statement in this file. It is a client component rendering WebGL to a canvas, and it responds to dragging, which makes it a test of three things at once: that a registered component resolves, that a 'use client' component can be mounted inside a server-rendered MDX page, and that an interactive canvas survives hydration inside the prose container.

9.2 Components taking props

NeuralManifold accepts size, backgroundClassName, and transparentBackground. Props pass through the MDX compiler unchanged, including expression props in braces, so a component may be configured from the MDX source in the ordinary way.

10. Footnotes

Footnotes are provided by remark-gfm and are collected into an automatically titled section at the foot of the page, which is why this heading is numbered rather than named for them.1 A second reference confirms the numbering and the back-links.2

Footnotes

  1. The return arrow at the end of a footnote navigates back to its reference in the body text.

  2. Footnotes may contain inline code, bold text, and links.