note

This rune is part of @refrakt-md/media. Install with npm install @refrakt-md/media and add "@refrakt-md/media" to the packages array in your refrakt.config.json.

Playlist

Curated track listings for albums, podcasts, audiobooks, and mixes. A heading becomes the playlist title, an image becomes the cover art, a paragraph becomes the description, and a list becomes the track listing. Bold text in each list item is the track name, parenthetical text is the duration, and italic text is the per-track artist.

Basic usage

An album with an artist and track listing.

{% playlist type="album" artist="Pink Floyd" layout="split" %}
# The Dark Side of the Moon

A landmark progressive rock album exploring themes of time, death, and madness.

- **Speak to Me** (1:13)
- **Breathe** (2:43)
- **On the Run** (3:36)
- **Time** (7:05)
- **The Great Gig in the Sky** (4:44)

---

![The Dark Side of the Moon](https://assets.refrakt.md/playlist-dark-side-of-the-moon.png)
{% /playlist %}
<section data-field="content-section" data-rune="playlist" typeof="MusicPlaylist">
  <meta content="album" data-field="type">
  <meta content="split" data-field="layout">
  <meta content="1 1" data-field="ratio">
  <meta content="top" data-field="valign">
  <meta content="Pink Floyd" data-field="artist" property="byArtist">
  <div data-name="media">
    <img src="https://assets.refrakt.md/playlist-dark-side-of-the-moon.png" alt="The Dark Side of the Moon" property="image">
  </div>
  <div data-name="content">
    <header>
      <h1 id="the-dark-side-of-the-moon" data-name="headline" property="name">The Dark Side of the Moon</h1>
      <p data-name="blurb">A landmark progressive rock album exploring themes of time, death, and madness.</p>
    </header>
    <ol data-name="tracks">
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Speak to Me</span>
        <span data-name="track-artist" property="byArtist">Pink Floyd</span>
        <span data-name="track-duration">1:13</span>
        <meta property="duration" content="PT73S">
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Breathe</span>
        <span data-name="track-artist" property="byArtist">Pink Floyd</span>
        <span data-name="track-duration">2:43</span>
        <meta property="duration" content="PT163S">
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">On the Run</span>
        <span data-name="track-artist" property="byArtist">Pink Floyd</span>
        <span data-name="track-duration">3:36</span>
        <meta property="duration" content="PT216S">
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Time</span>
        <span data-name="track-artist" property="byArtist">Pink Floyd</span>
        <span data-name="track-duration">7:05</span>
        <meta property="duration" content="PT425S">
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">The Great Gig in the Sky</span>
        <span data-name="track-artist" property="byArtist">Pink Floyd</span>
        <span data-name="track-duration">4:44</span>
        <meta property="duration" content="PT284S">
      </li>
    </ol>
  </div>
</section>
album
The Dark Side of the Moon

The Dark Side of the Moon

A landmark progressive rock album exploring themes of time, death, and madness.

  1. Speak to MePink Floyd1:13
  2. BreathePink Floyd2:43
  3. On the RunPink Floyd3:36
  4. TimePink Floyd7:05
  5. The Great Gig in the SkyPink Floyd4:44
<section data-field="content-section" typeof="MusicPlaylist" class="rf-playlist rf-playlist--album rf-playlist--split" data-type="album" data-layout="split" data-ratio="1 1" data-valign="top" data-gap="default" data-artist="Pink Floyd" data-rune="playlist" data-density="full" data-media-position="top" style="--split-ratio: 1fr 1fr; --split-valign: start; --split-gap: var(--rf-spacing-md)">
  <div data-name="meta" class="rf-playlist__meta" data-section="header">
    <span data-name="type-badge" data-meta-type="category" data-meta-rank="primary" class="rf-playlist__type-badge">album</span>
  </div>
  <div data-name="media" class="rf-playlist__media" data-section="media" data-media="cover">
    <img src="https://assets.refrakt.md/playlist-dark-side-of-the-moon.png" alt="The Dark Side of the Moon" property="image" />
  </div>
  <div data-name="content" class="rf-playlist__content">
    <header data-name="preamble" class="rf-playlist__preamble" data-section="preamble">
      <h1 id="the-dark-side-of-the-moon" data-name="headline" property="name" class="rf-playlist__headline" data-section="title">The Dark Side of the Moon</h1>
      <p data-name="blurb" class="rf-playlist__blurb" data-section="description">A landmark progressive rock album exploring themes of time, death, and madness.</p>
    </header>
    <ol data-name="tracks" class="rf-playlist__tracks" data-sequence="numbered">
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Speak to Me</span>
        <span data-name="track-artist" property="byArtist">Pink Floyd</span>
        <span data-name="track-duration">1:13</span>
        <meta property="duration" content="PT73S" />
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Breathe</span>
        <span data-name="track-artist" property="byArtist">Pink Floyd</span>
        <span data-name="track-duration">2:43</span>
        <meta property="duration" content="PT163S" />
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">On the Run</span>
        <span data-name="track-artist" property="byArtist">Pink Floyd</span>
        <span data-name="track-duration">3:36</span>
        <meta property="duration" content="PT216S" />
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Time</span>
        <span data-name="track-artist" property="byArtist">Pink Floyd</span>
        <span data-name="track-duration">7:05</span>
        <meta property="duration" content="PT425S" />
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">The Great Gig in the Sky</span>
        <span data-name="track-artist" property="byArtist">Pink Floyd</span>
        <span data-name="track-duration">4:44</span>
        <meta property="duration" content="PT284S" />
      </li>
    </ol>
  </div>
</section>

Podcast

Use type="podcast" for episodic content with dates.

{% playlist type="podcast" %}
# Design Systems Weekly

A podcast about building and scaling design systems.

- **Component Libraries at Scale** (45:30) — March 2025
- **Token Architecture** (38:15) — February 2025
- **Accessibility First** (42:00) — January 2025
{% /playlist %}
<section data-field="content-section" data-rune="playlist" typeof="MusicPlaylist">
  <meta content="podcast" data-field="type">
  <meta content="stacked" data-field="layout">
  <div data-name="content">
    <header>
      <h1 id="design-systems-weekly" data-name="headline" property="name">Design Systems Weekly</h1>
      <p data-name="blurb">A podcast about building and scaling design systems.</p>
    </header>
    <ol data-name="tracks">
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Component Libraries at Scale</span>
        <span data-name="track-duration">45:30</span>
        <meta property="duration" content="PT2730S">
        <span data-name="track-meta" property="datePublished">March 2025</span>
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Token Architecture</span>
        <span data-name="track-duration">38:15</span>
        <meta property="duration" content="PT2295S">
        <span data-name="track-meta" property="datePublished">February 2025</span>
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Accessibility First</span>
        <span data-name="track-duration">42:00</span>
        <meta property="duration" content="PT2520S">
        <span data-name="track-meta" property="datePublished">January 2025</span>
      </li>
    </ol>
  </div>
</section>
podcast

Design Systems Weekly

A podcast about building and scaling design systems.

  1. Component Libraries at Scale45:30March 2025
  2. Token Architecture38:15February 2025
  3. Accessibility First42:00January 2025
<section data-field="content-section" typeof="MusicPlaylist" class="rf-playlist rf-playlist--podcast rf-playlist--stacked" data-type="podcast" data-layout="stacked" data-ratio="1 1" data-valign="top" data-gap="default" data-rune="playlist" data-density="full" data-media-position="top" style="--split-ratio: 1fr 1fr; --split-valign: start; --split-gap: var(--rf-spacing-md)">
  <div data-name="meta" class="rf-playlist__meta" data-section="header">
    <span data-name="type-badge" data-meta-type="category" data-meta-rank="primary" class="rf-playlist__type-badge">podcast</span>
  </div>
  <div data-name="content" class="rf-playlist__content">
    <header data-name="preamble" class="rf-playlist__preamble" data-section="preamble">
      <h1 id="design-systems-weekly" data-name="headline" property="name" class="rf-playlist__headline" data-section="title">Design Systems Weekly</h1>
      <p data-name="blurb" class="rf-playlist__blurb" data-section="description">A podcast about building and scaling design systems.</p>
    </header>
    <ol data-name="tracks" class="rf-playlist__tracks" data-sequence="numbered">
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Component Libraries at Scale</span>
        <span data-name="track-duration">45:30</span>
        <meta property="duration" content="PT2730S" />
        <span data-name="track-meta" property="datePublished">March 2025</span>
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Token Architecture</span>
        <span data-name="track-duration">38:15</span>
        <meta property="duration" content="PT2295S" />
        <span data-name="track-meta" property="datePublished">February 2025</span>
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Accessibility First</span>
        <span data-name="track-duration">42:00</span>
        <meta property="duration" content="PT2520S" />
        <span data-name="track-meta" property="datePublished">January 2025</span>
      </li>
    </ol>
  </div>
</section>

Per-track artists

When tracks have different artists, use italic text for per-track attribution. Omit the artist attribute to avoid a default.

{% playlist type="mix" %}
# Summer Vibes 2025

- **Midnight City** (4:03) *M83*
- **Electric Feel** (3:49) *MGMT*
- **Do I Wanna Know?** (4:32) *Arctic Monkeys*
- **Intro** (4:18) *The xx*
{% /playlist %}
<section data-field="content-section" data-rune="playlist" typeof="MusicPlaylist">
  <meta content="mix" data-field="type">
  <meta content="stacked" data-field="layout">
  <div data-name="content">
    <header>
      <h1 id="summer-vibes-2025" data-name="headline" property="name">Summer Vibes 2025</h1>
    </header>
    <ol data-name="tracks">
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Midnight City</span>
        <span data-name="track-artist" property="byArtist">M83</span>
        <span data-name="track-duration">4:03</span>
        <meta property="duration" content="PT243S">
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Electric Feel</span>
        <span data-name="track-artist" property="byArtist">MGMT</span>
        <span data-name="track-duration">3:49</span>
        <meta property="duration" content="PT229S">
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Do I Wanna Know?</span>
        <span data-name="track-artist" property="byArtist">Arctic Monkeys</span>
        <span data-name="track-duration">4:32</span>
        <meta property="duration" content="PT272S">
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Intro</span>
        <span data-name="track-artist" property="byArtist">The xx</span>
        <span data-name="track-duration">4:18</span>
        <meta property="duration" content="PT258S">
      </li>
    </ol>
  </div>
</section>
mix

Summer Vibes 2025

  1. Midnight CityM834:03
  2. Electric FeelMGMT3:49
  3. Do I Wanna Know?Arctic Monkeys4:32
  4. IntroThe xx4:18
<section data-field="content-section" typeof="MusicPlaylist" class="rf-playlist rf-playlist--mix rf-playlist--stacked" data-type="mix" data-layout="stacked" data-ratio="1 1" data-valign="top" data-gap="default" data-rune="playlist" data-density="full" data-media-position="top" style="--split-ratio: 1fr 1fr; --split-valign: start; --split-gap: var(--rf-spacing-md)">
  <div data-name="meta" class="rf-playlist__meta" data-section="header">
    <span data-name="type-badge" data-meta-type="category" data-meta-rank="primary" class="rf-playlist__type-badge">mix</span>
  </div>
  <div data-name="content" class="rf-playlist__content">
    <header data-name="preamble" class="rf-playlist__preamble" data-section="preamble">
      <h1 id="summer-vibes-2025" data-name="headline" property="name" class="rf-playlist__headline" data-section="title">Summer Vibes 2025</h1>
    </header>
    <ol data-name="tracks" class="rf-playlist__tracks" data-sequence="numbered">
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Midnight City</span>
        <span data-name="track-artist" property="byArtist">M83</span>
        <span data-name="track-duration">4:03</span>
        <meta property="duration" content="PT243S" />
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Electric Feel</span>
        <span data-name="track-artist" property="byArtist">MGMT</span>
        <span data-name="track-duration">3:49</span>
        <meta property="duration" content="PT229S" />
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Do I Wanna Know?</span>
        <span data-name="track-artist" property="byArtist">Arctic Monkeys</span>
        <span data-name="track-duration">4:32</span>
        <meta property="duration" content="PT272S" />
      </li>
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Intro</span>
        <span data-name="track-artist" property="byArtist">The xx</span>
        <span data-name="track-duration">4:18</span>
        <meta property="duration" content="PT258S" />
      </li>
    </ol>
  </div>
</section>

With chapter markers

Tracks can include nested lists for chapter markers or lyrics. Use content="chapters" or content="lyrics" to force the display mode, or leave it as auto for automatic detection.

{% playlist type="podcast" content="chapters" %}
# Tech Talk: Web Components

- **Episode 42: Shadow DOM Deep Dive** (1:02:15)
  1. **Introduction** (0:00) Overview of today's topic
  2. **What is Shadow DOM?** (3:45) Core concepts explained
  3. **Styling strategies** (18:30) CSS custom properties and parts
  4. **Q&A** (45:00) Listener questions
{% /playlist %}
<section data-field="content-section" data-rune="playlist" typeof="MusicPlaylist">
  <meta content="podcast" data-field="type">
  <meta content="stacked" data-field="layout">
  <div data-name="content">
    <header>
      <h1 id="tech-talk:-web-components" data-name="headline" property="name">Tech Talk: Web Components</h1>
    </header>
    <ol data-name="tracks">
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Episode 42: Shadow DOM Deep Dive</span>
        <span data-name="track-duration">1:02:15</span>
        <meta property="duration" content="PT3735S">
        <ol data-name="chapters">
          <li data-time="0">
            <span data-name="chapter-name">Introduction</span>
            <span data-name="chapter-time">0:00</span>
          </li>
          <li data-time="225">
            <span data-name="chapter-name">What is Shadow DOM?</span>
            <span data-name="chapter-time">3:45</span>
          </li>
          <li data-time="1110">
            <span data-name="chapter-name">Styling strategies</span>
            <span data-name="chapter-time">18:30</span>
          </li>
          <li data-time="2700">
            <span data-name="chapter-name">Q&amp;A</span>
            <span data-name="chapter-time">45:00</span>
          </li>
        </ol>
      </li>
    </ol>
  </div>
</section>
podcast

Tech Talk: Web Components

  1. Episode 42: Shadow DOM Deep Dive1:02:15
    1. Introduction0:00
    2. What is Shadow DOM?3:45
    3. Styling strategies18:30
    4. Q&A45:00
<section data-field="content-section" typeof="MusicPlaylist" class="rf-playlist rf-playlist--podcast rf-playlist--stacked" data-type="podcast" data-layout="stacked" data-ratio="1 1" data-valign="top" data-gap="default" data-rune="playlist" data-density="full" data-media-position="top" style="--split-ratio: 1fr 1fr; --split-valign: start; --split-gap: var(--rf-spacing-md)">
  <div data-name="meta" class="rf-playlist__meta" data-section="header">
    <span data-name="type-badge" data-meta-type="category" data-meta-rank="primary" class="rf-playlist__type-badge">podcast</span>
  </div>
  <div data-name="content" class="rf-playlist__content">
    <header data-name="preamble" class="rf-playlist__preamble" data-section="preamble">
      <h1 id="tech-talk:-web-components" data-name="headline" property="name" class="rf-playlist__headline" data-section="title">Tech Talk: Web Components</h1>
    </header>
    <ol data-name="tracks" class="rf-playlist__tracks" data-sequence="numbered">
      <li typeof="MusicRecording" data-field="track" property="track">
        <span data-name="track-name" property="name">Episode 42: Shadow DOM Deep Dive</span>
        <span data-name="track-duration">1:02:15</span>
        <meta property="duration" content="PT3735S" />
        <ol data-name="chapters">
          <li data-time="0">
            <span data-name="chapter-name">Introduction</span>
            <span data-name="chapter-time">0:00</span>
          </li>
          <li data-time="225">
            <span data-name="chapter-name">What is Shadow DOM?</span>
            <span data-name="chapter-time">3:45</span>
          </li>
          <li data-time="1110">
            <span data-name="chapter-name">Styling strategies</span>
            <span data-name="chapter-time">18:30</span>
          </li>
          <li data-time="2700">
            <span data-name="chapter-name">Q&amp;A</span>
            <span data-name="chapter-time">45:00</span>
          </li>
        </ol>
      </li>
    </ol>
  </div>
</section>

Attributes

AttributeTypeDefaultDescription
typestringalbumPlaylist type: album, podcast, audiobook, series, or mix
artiststringDefault artist applied to all tracks
playerbooleanShow an embedded audio player
contentstringautoCue point display: auto, lyrics, or chapters
idstringIdentifier for connecting an audio player rune

Section header

Playlist supports an optional eyebrow, headline, and blurb above the playlist content. Place a short paragraph or heading before the main content to use them. See Page sections for the full syntax.

Common attributes

All block runes share these attributes for layout and theming.

AttributeTypeDefaultDescription
widthstringcontentPage grid width: content, wide, or full
spacingstringVertical spacing: flush, tight, default, loose, or breathe
insetstringHorizontal padding: flush, tight, default, loose, or breathe
tintstringNamed colour tint from theme configuration
tint-modestringautoColour scheme override: auto, dark, or light
bgstringNamed background preset from theme configuration