Playful Programming has a number of features that extend the Markdown syntax to make it more powerful and expressive.
Our base markdown syntax is based on the GitHub Flavored Markdown specification. This includes support for:
- Headings
- Images
- Links
- Code Blocks
- Tables
- Alerts
However, we've extended many of these base features.
Markdown headings usually have a 1:1 relationship with the HTML <h1>
, <h2>
, <h3>
, <h4>
, <h5>
, and <h6>
tags.
However, in Playful Programming, we move the heading level down by one for accessibility reasons.
This means that the highest level heading in Playful Programming is an <h2>
tag, and the lowest level heading is an <h6>
tag.
# Heading 1
becomes<h2>Heading 1</h2>
## Heading 2
becomes<h3>Heading 2</h3>
### Heading 3
becomes<h4>Heading 3</h4>
#### Heading 4
becomes<h5>Heading 4</h5>
##### Heading 5
becomes<h6>Heading 5</h6>
###### Heading 6
becomes<h6>Heading 6</h6>
We support the ability to set custom IDs for stable deep linking in an article using the following syntax:
# Heading {#some-id}
Relative image paths are resolved relative to the markdown file that contains the image.

We also:
- Transform the image into a
picture
element to support multiple sources. - Resize the image automatically to fit the screen.
- The maximum width is 896px.
- The maximum height is 768px.
- The aspect ratio is preserved.
- Generate
avi
andwebp
versions of the image to improve performance. - Automatically add a
loading="lazy"
attribute to all images to improve performance. - Add decoding
async
to all images to improve performance.
We, by default, add the ability to click on an image to zoom in on it. This is useful for showing off details in an image.
You can disable this feature by adding the data-nozoom
attribute to the image:
<img src="./image.png" data-nozoom />
Or customize the image to zoom into for a higher-resolution version:
<img src="./image.png" data-zoom-src="./hq-image.png" />
Links in Playful Programming are the same as in GitHub Flavored Markdown, but we mark external links with some properties:
target="_blank"
: Opens the link in a new tabrel="noopener noreferrer"
: Prevents the new tab from accessing thewindow.opener
property
Tables in Playful Programming are the same as in GitHub Flavored Markdown, but we add support for sticky headers when the table is too long to fit on the screen.
We use Shiki to highlight code blocks in markdown files. This means that we support over 100 languages and light and dark mode themes.
We also support the following features:
- Line highlighting
"[!code highlight]"
- "``` {1,3-4}"
- Line numbers
We support a number of HTML elements that are transformed into more complex components:
- Videos
- IFrames
- Summary Blocks
You can embed videos in your markdown files using the following syntax:
<video src="./video.mp4" title="The alt text of the video" />
This will set the default values of the video to true
:
muted
autoPlay
controls
loop
You can embed iframes in your markdown files using the following syntax:
<iframe src="https://example.com" data-frame-title="The heading text of the iframe" />
We make this iframe lazy-loaded by default and force the user to click to run the contents for performance reasons.
We also lookup the websites favicon and use it as the icon for the iframe.
We support loading full code projects into iframes via StackBlitz projects. This is useful for showing off code samples in a live environment.
To start, create a full project into a sub-folder of the markdown file. Then, add the following code block to the markdown file:
<iframe data-frame-title="React Transparent Files Before - StackBlitz" src="pfp-code:./my-folder"></iframe>
We pass all URL parameters to the StackBlitz project, so you can use them to customize the project.
Summary blocks are a way to show a summary of a section of content. They are useful for showing off the main points of a section.
<details>
<summary>Title</summary>
Hidden content
</details>
Like MDX, Playful Programming supports the use of components in markdown files. Unlike MDX, we use a different syntax to define components and do not use React or JSX.
The filetree component is used to display a file tree in the markdown file. It is useful for showing the structure of a project or the contents of a directory.
<!-- ::start:filetree -->
- `public/`
- `src/`
- `assets/{open: false}`
- ...
- `index.html`
- **`index.js`**
- `styles.css` A style file that we can use later
- `package.json`
<!-- ::end:filetree -->
It is required to use inline code blocks for files and folders names.
The filetree component supports the following:
- Icons for files and folders are automatically added
- Folders are denoted by a trailing
/
- folder/{open: false}
to denote a closed folder- Folders are open by default
- ...
to denote more contents are omitted inside a folder- **File**
to highlight a file or folder- Comments are added after-the-fact
While not 1:1, the filetree component is inspired by the Astro Starlight file-tree
component
We support showing ads in the content of the article. This is useful for promoting products, services, or donations.
<!-- ::in-content-ad title="Consider supporting" body="Donating any amount will help towards further development of articles like this." button-text="Visit our Open Collective" button-href="https://opencollective.com/playfulprogramming" -->
We support the following properties:
title
: The title of the adbody
: The body of the adbutton-text
: The text of the buttonbutton-href
: The URL that the button links to
Tabs are a way to organize content in a tabbed interface. They are useful for organizing content that is related but not necessarily sequential.
<!-- ::start:tabs -->
# Tab 1
This is the content of tab 1.
# Tab 2
This is the content of tab 2.
# Tab 3
This is the content of tab 3.
<!-- ::end:tabs -->
Tabs take the top-level heading as the tab title, but leaves lower-level headings as they are.
<!-- ::start:tabs -->
# Tab 1
This is the content of tab 1.
# Tab 2
This is the content of tab 2.
# Tab 3
This is the content of tab 3.
<!-- ::end:tabs -->
We auto-generate an EPUB file for all article collections. This allows you to read contents from Playful Programming on-the-go with an ereader.
Just go to:
https://playfulprogramming.com/YOUR-COLLECTION-SLUG-HERE.epub
To get the EPUB for the related collection.
We support customizing the contents of the epub by hiding or exlusively showing parts of a markdown file from the generated epub:
<!-- ::start:no-ebook -->
This is missing from the EPUB
<!-- ::end:no-ebook -->
<!-- ::start:only-ebook -->
This is missing from the website
<!-- ::end:only-ebook -->
We support adding metadata to an article or collection via a JS-object "frontmatter":
---
{
title: "A title",
published: '2023-03-25',
tags: ['opinion']
}
---
Article contents here
We support the following properties on a post:
title
: The title of the articlepublished
: The publication date of the article- Must be an ISO timestamp of
YYYY-MM-DD
- Must be an ISO timestamp of
authors
: A list of ids of the related authors- Only used when there's multiple authors per article. Must list all authors, including the one the post is in the folder of.
tags
: A list of tags the post relates to- Must match one of these tags.
license
: A string of what license to attribute the post to- Must match one of these license IDs.
description
: The description of the article- Without this present, one will auto-generate for you based on the first ~160 characters of the post
edited
: When an article was edited last- Optional.
- Must be an ISO timestamp of
YYYY-MM-DD
collection
: The name of the series the post is associated with- If you need to add more metadata than this, please create a folder of
collections
and put anindex.md
file there with said metadata. Then place the post in theposts
subfolder of the collection.
- If you need to add more metadata than this, please create a folder of
order
: The order of which the article is within a collection- Only used when inside of a collection
originalLink
: The canonical link of the post, where it was originally posted.- Required if the post is a cross-post
noindex
: Should the article be hidden from the site's list view,sitemap
, and search?- Useful for draft or archived content
upToDateSlug
: The latest published version of the articleversion
: The version of the article- IE:
v1
,v3.5
, etc - Useful when combined with
upToDateSlug
andnoindex
- IE:
title
: The title of the collectiondescription
: The description of the collection- Unlike posts, without one nothing will auto-generate for you.
authors
: A list of ids of the related authors- Only used when there's multiple authors per article. Must list all authors, including the one the post is in the folder of.
coverImg
: The cover image of the collection- Used in EPUB generation for the cover
- Used in the auto-generated page as the top image
socialImg
: The image used in social media preview pages- If unused,
coverImg
will be used instead
- If unused,
type
: The type of collection it is"book"
- Used for SEO- Nothing (defualt) - Unused
pageLayout
:"none"
- Do not auto-generate a page for this collection- Useful for custom pages like The Framework Field Guide
- Nothing (defualt) - auto-generate a page for the collection
customChaptersText
: The custom text to be used in the "A part of a series" texttags
: A list of related tags- Must match one of these tags.
published
: The publication date of the article- Must be an ISO timestamp of
YYYY-MM-DD
- Must be an ISO timestamp of
buttons
: A list of buttons to show on the auto-generated page- Must be an array of
{text: string, url: string}
- Must be an array of
chapterList
: A list of extra chapters to include in addition to the auto-discovered ones- Must be an array of
{title: string;description: string;order: string;}
- Must be an array of
noindex
: Should the collection be hidden from the site's list view,sitemap
, and search?- Useful for draft or archived content
upToDateSlug
: The latest published version of the collectionversion
: The version of the collection- IE:
v1
,v3.5
, etc - Useful when combined with
upToDateSlug
andnoindex
- IE: