Skip to main content
/

Style Guide

Jacob Coffee, Cody Fincher & Janek Nouvertné··Updated: Jan 2026·2.8k words·26 min read·

A comprehensive style guide showcasing every MDX component, markdown feature, and styling option available on scriptr.dev. Use this as a reference for writing blog posts.

This is my site's styleguide page, showcasing all the custom components and how everything flows together for blog content. This is edited using Keystatic on https://scriptr.dev/keystatic.


Typography & Text Formatting

Regular paragraph text looks like this. It uses a comfortable line height and muted foreground color for easy reading.

Bold text is used for emphasis. Italic text is used for subtle emphasis. You can also combine bold and italic together.

Inline code snippets are styled with a monospace font and subtle background. Great for mentioning function_names(), variables, or file.py paths.


Headings

Heading 1 (H1)

Heading 2 (H2)

Heading 3 (H3)

Heading 4 (H4)

Heading 5 (H5)
Heading 6 (H6)


Lists

Unordered List

  • First item in the list
  • Second item with some bold text
  • Third item with inline code
    • Nested item one
    • Nested item two
      • Deeply nested item
  • Fourth item

Ordered List

  1. First step in the process
  2. Second step with emphasis
  3. Third step
    1. Sub-step A
    2. Sub-step B
  4. Fourth step with a link

This is a long paragraph of text designed to test how content wraps around the floated sidebar cards on the right side of the page. When you have floated elements like the author card and the "mentioned" sidebar, the text should flow naturally around them, creating a magazine-style layout. This paragraph contains enough words to demonstrate the wrapping behavior across multiple lines. The text should hug the left edge of the floated elements and then expand to full width once it clears them. This is particularly important for readability and visual balance in blog posts that contain rich metadata sidebars. We want to ensure that paragraphs, lists, code blocks, and other content elements all respect the float boundaries properly without any awkward overlapping or visual glitches.

The goal is a clean, professional reading experience that makes good use of the available horizontal space while keeping supplementary information accessible in the sidebar. Additionally, this extended content helps verify that the CSS float clearing behavior works correctly once the text extends beyond the height of the sidebar elements. When the paragraph becomes long enough to pass the bottom edge of the floated content, the remaining text should expand to use the full available width of the content area. This creates a natural, flowing document structure that feels intuitive to readers who are accustomed to magazine and newspaper layouts. The transition from wrapped text to full-width text should be seamless, without any jarring jumps or layout shifts.

Furthermore, this test paragraph helps ensure that line heights, letter spacing, and word spacing remain consistent throughout the entire block of text, regardless of whether it's wrapping around floated elements or expanding to full width. Good typography requires attention to these details across all edge cases and layout configurations. Finally, testing with various viewport widths is essential to ensure that responsive breakpoints handle the float clearing gracefully, collapsing the sidebar on mobile while preserving the wrap behavior on larger screens where space permits.

Beyond viewport testing, this paragraph also serves to validate that text selection, copy-paste behavior, and accessibility features work correctly when content flows around floated elements. Screen readers should announce the content in logical reading order, and keyboard navigation should allow users to tab through interactive elements without confusion caused by the visual float layout. The interplay between semantic HTML structure and CSS visual presentation is crucial here, as the DOM order must remain sensible even when floats create a non-linear visual flow. Print stylesheets should also be considered, ensuring that when users print the page, the floated sidebars either collapse inline or are positioned appropriately for paper output.

Task List (GitHub-style)

  • [x] Completed task
  • [x] Another done item
  • [ ] Pending task
  • [ ] Future work

Blockquotes

This is a simple blockquote. Great for highlighting important information or quoting someone.

Pro Tip: You can include formatting inside blockquotes too!

Even multiple paragraphs work.

See #2741 for the pull request that inspired this.


Code Blocks

Python

from litestar import Litestar, get
from litestar.di import Provide
 
async def get_db_connection() -> AsyncGenerator[Connection, None]:
    """Dependency that provides a database connection."""
    async with pool.acquire() as conn:
        yield conn
 
@get("/users/{user_id:int}")
async def get_user(user_id: int, db: Connection) -> User:
    """Fetch a user by ID from the database."""
    return await db.fetch_one(
        "SELECT * FROM users WHERE id = $1",
        user_id
    )
 
app = Litestar(
    route_handlers=[get_user],
    dependencies={"db": Provide(get_db_connection)},
)

TypeScript/React

import { useState, useEffect } from "react";
 
interface User {
  id: number;
  name: string;
  email: string;
}
 
export function UserProfile({ userId }: { userId: number }) {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);
 
  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then((res) => res.json())
      .then((data) => {
        setUser(data);
        setLoading(false);
      });
  }, [userId]);
 
  if (loading) return <div>Loading...</div>;
  if (!user) return <div>User not found</div>;
 
  return (
    <div className="p-4 border rounded-lg">
      <h2 className="text-xl font-bold">{user.name}</h2>
      <p className="text-muted-foreground">{user.email}</p>
    </div>
  );
}

Shell/Bash

# Install uv (the fast Python package manager)
curl -LsSf https://astral.sh/uv/install.sh | sh
 
# Create a new project
uv init my-project
cd my-project
 
# Add dependencies
uv add litestar uvicorn
 
# Run the application
uv run python -m uvicorn main:app --reload

YAML

name: CI Pipeline
on:
  push:
    branches: [main]
  pull_request:
 
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v4
      - run: uv sync
      - run: uv run pytest

JSON

{
  "name": "scriptr-prime",
  "version": "1.0.0",
  "dependencies": {
    "next": "^15.0.0",
    "react": "^19.0.0",
    "tailwindcss": "^4.0.0"
  }
}

SQL

SELECT
    u.id,
    u.username,
    COUNT(p.id) as post_count,
    MAX(p.created_at) as last_post_date
FROM users u
LEFT JOIN posts p ON p.author_id = u.id
WHERE u.active = true
GROUP BY u.id, u.username
HAVING COUNT(p.id) > 5
ORDER BY post_count DESC
LIMIT 10;

Callouts


Multi-Author Components

AuthorSection

Attribute prose sections to specific authors in multi-author posts. The author's avatar and name float as a sidebar, with text flowing around it. The about_authors sidebar shows a count of sections per author with navigation arrows to jump between them.

Ee Durbin
Ee Durbin

This is the first section from Ee. The author badge floats to the left and the prose wraps around it naturally. Use this for co-authored retrospectives, interviews, or any post where multiple voices contribute distinct sections.

Jacob Coffee
Jacob Coffee

This is the first section from Jacob, positioned on the right side. Alternate between side="left" (default) and side="right" for visual variety.

Ee Durbin
Ee Durbin

This is Ee's second section. Notice the section count in the about_authors sidebar updates to show "2 sections" for Ee. Use the arrows to jump between an author's sections.

Jacob Coffee
Jacob Coffee

And this is Jacob's second section. The navigation arrows let readers quickly move between sections from the same author, helpful in long multi-author posts.

Ee Durbin
Ee Durbin

Here's a third section from Ee to demonstrate navigation with multiple sections. Click the section count or use the arrows in the sidebar!

ConversationThread

For back-and-forth dialogue between people. Hover an avatar to highlight all messages from that speaker:

ScheduledPostCard

Preview card for posts that are scheduled but not yet released. This is automatically shown on scheduled posts, but you can demo it here:

ScheduledPostCard demo removed - incompatible with Keystatic MDX parser (JSX array expressions not supported)


Tables

Simple Table

Complex Table


Package & Repository References

PyPI Packages (Python)

Here are some popular Python packages: litestar, fastapi, django, and flask.

For tooling, check out uv (fast installer), ruff, and pytest.

NPM Packages (JavaScript)

Frontend favorites: react, Next.js, and Tailwind CSS.


Python.org Pages

Link to the Python Software Foundation or the downloads page.

Direct URLs work too: PSF Community Awards

Python Documentation

Reference the asyncio module or Python Tutorial.

Direct doc URLs: What's New in 3.12

PEP References

Reference Python Enhancement Proposals with just a number: PEP 8 or PEP 484 or PEP 3000.

Show the full title: PEP 20: The Zen of Python or PEP 572: Assignment Expressions.

Custom labels work too: type hints PEP or see PEP 810 for lazy imports.

Link to any docs site: Litestar Docs

More examples: React Learn, Next.js Docs


GitHub References

Users

Shoutout to the Litestar maintainers: @JacobCoffee and @provinzkraut.

With avatars: JacobCoffee's avatar@JacobCoffee, adamchainz's avatar@adamchainz

Repositories

Check out these repos: litestar, uv, CPython

Issues & Pull Requests

Reference issues: #1234 or with custom text: CPython issue about typing

Reference PRs: #2741 or with custom text: The big refactor PR


Bluesky

Follow me on @scriptr.dev for updates!

Or with custom text: Follow @scriptr on Bluesky

Twitter/X

Follow on @_scriptr or X (formerly Twitter)

LinkedIn

Connect on JacobCoffee or LinkedIn profile

Mastodon

Find me on Fosstodon

YouTube

Watch Django 5.x overview from JetBrains

Or just: My YouTube channel


Link to sponsors and funding sources with a distinctive pink/purple gradient style:

Basic sponsor: Alpha-OmegaBronze

With tier badge: AnthropicDiamond

The <Sponsor> component is perfect for crediting funding sources in blog posts about open source work.


Internal Site References

Link to pages within the site using amber-styled badges with arrow icons (distinct from external links).

Page References

Link to main site pages: Home, Blog, Talks, Projects, CV, Homelab

With custom labels: my talks or the blog

Blog Post References

Link to specific blog posts: python org django 5 upgrade or with a label: my Django upgrade post

Talk References

Link to talks: pytexas 2026 the bakery pep810 or my PyTexas talk

CV References

Link to CV: experience or to specific sections: experience, my skills

Project References

Link to projects: litestar or Litestar Framework


Combined Examples

Here's how you might use multiple components in a real blog post:

I recently contributed a Django upgrade to the Python.org codebase. Huge thanks to @adamchainz for the django-upgrade tool!

The upgrade involved updating django from 4.2 to 5.2, along with dependencies like django-pipeline.


Footnotes

Footnotes are a great way to add citations, clarifications, or tangential information without disrupting the flow of your writing1.

You can use multiple footnotes2 throughout your content, and they will be numbered automatically.

Footnotes can contain longer explanations3 when you need to elaborate on something without cluttering the main text.

They work great for academic citations4 and technical references5.


Horizontal Rules

Content above the rule.


Content below the rule.


Alternative rule syntax also works.


Escaping & Special Characters

In MDX, use backslash escapes or HTML entities for literal special characters:

  • Asterisks: Use \* → *asterisk*
  • Backticks: Use HTML entity &#96; → `backtick`
  • Underscores: Use \_ → _underscore_
  • Brackets: Use \[ and \] → [not a link]

HTML entities: &amp; & · &lt; < · &gt; > · &copy; © · &mdash; — · &rarr;


Tooltips

Add hover tooltips with optional visual indicator (dotted underline):

This is a hoverable term in a sentence.

Without indicator (no visual hint): plain text


Forms

CabotageInterestForm

Collect interest for PSF Cabotage hosting. Submits to Google Sheets with email notification:


Conclusion

This page demonstrates all the MDX components and markdown features available for blog posts.

Quick Reference:

Package References:

  • Use <PyPi name="package" /> for Python packages
  • Use <Npm name="package" /> for NPM packages

Documentation Links:

  • Use <Pep number={8} /> for PEP references (with optional showTitle or label)
  • Use <PythonOrg path="psf" /> for Python.org pages
  • Use <PythonDocs path="library/asyncio" /> for Python docs
  • Use <Docs href="url" site="name" /> for any documentation site

GitHub References:

  • Use <GhUser name="username" /> for GitHub users
  • Use <GhRepo repo="owner/repo" /> for repositories
  • Use <GhIssue issue="owner/repo#123" /> for issues
  • Use <GhPr pr="owner/repo#123" /> for pull requests

Social Links:

  • Use <Bluesky handle="user" /> for Bluesky
  • Use <Twitter handle="user" /> for X/Twitter
  • Use <LinkedIn handle="user" /> for LinkedIn
  • Use <Mastodon href="url">label</Mastodon> for Mastodon/Fosstodon
  • Use <YouTube href="url" /> for YouTube

Internal Site References:

  • Use <PageRef page="talks" /> for internal page links
  • Use <BlogRef slug="post-slug" /> for blog post links
  • Use <TalkRef slug="talk-slug" /> for talk links
  • Use <CVRef section="experience" /> for CV section links
  • Use <ProjectRef name="project" /> for project links

Multi-Author:

  • Use <AuthorSection name="Name" avatar="url">content</AuthorSection> for floated author attribution
  • Use <ConversationThread><Message speaker="Name">text</Message></ConversationThread> for dialogue

Sponsors:

  • Use <Sponsor name="Name" href="url" /> for sponsor references
  • Use <Sponsor name="Name" href="url" tier="Diamond" /> with tier badge

Tooltips:

  • Use <Tooltip content="explanation" label="hover text" indicator /> for inline tooltips with visual indicator

Forms:

  • Use <CabotageInterestForm /> for PSF Cabotage hosting interest form

Other:

  • Use <Callout type="info|warning|error|success"> for callouts
  • Use [^id] for footnote references and [^id]: content for definitions
  • Use <ScheduledPostCard releaseDate="2026-01-23" title="..." /> for scheduled teasers

Frontmatter sidebar fields:

  • github_users, github_repos, github_issues, github_prs for GitHub references
  • pypi_packages, npm_packages for package references
  • sponsors (format: "name|url" or "name|url|logo") for sponsor mentions
  • external_links (format: "label|url") for external link references
  • author_ids for the author sidebar

Questions? Reach out via @scriptr.dev or @_scriptr!

Footnotes

  1. This is the first footnote. It appears as a popover when you hover over the reference!

  2. You can include formatting and inline code in footnotes too.

  3. Footnotes are especially useful when you want to provide additional context or sources without breaking the reader's flow. The popover feature lets readers quickly preview the footnote content without scrolling to the bottom of the page.

  4. See the Django documentation at https://docs.djangoproject.com for more details on the ORM.

  5. PEP 8 is the style guide for Python code. Read it at https://peps.python.org/pep-0008/.