npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fsegurai/marked-extended-slide

v17.0.0

Published

Extension for Marked.js that adds support for presentation slides, allowing the creation of slide-based presentations with Markdown. It supports layouts, backgrounds, transitions, nested rendering, and can be customized to fit your needs.

Readme

An extension library for Marked.js to enhance Markdown rendering.

@fsegurai/marked-extended-slide Extension for Marked.js that adds support for presentation slides, allowing the creation of slide-based presentations with Markdown. It supports layouts, backgrounds, transitions, nested rendering, and can be customized to fit your needs.

🎯 Overview

The marked-extended-slide extension transforms your Markdown into interactive presentation slides using explicit block syntax. It supports layouts, backgrounds, transitions, speaker notes, nested and custom extensions, and a programmatic navigation API.

✨ Key Features

  • 🎨 11 Built-in Layouts: Cover, two-cols, quote, statement, section, and more
  • 🌈 16 Pre-built Themes: Dark, light, Dracula, Nord, GitHub, Material, Tokyo Night, and more
  • 6 Transition Effects: Slide, fade, zoom, slide-up/down, or none
  • 📐 Responsive Design: Auto-scaling with configurable aspect ratios
  • ⌨️ Keyboard Navigation: Arrow keys, space, home/end, overview mode
  • 📱 Touch Navigation: Swipe support for mobile and tablets
  • 🎭 Custom Backgrounds: Solid colors, gradients, or images
  • 📊 Progress Tracking: Progress bar and slide numbers
  • 🎪 Nested Extensions: Full support for other marked extensions inside slides, including custom block and inline extensions

🎪 Live Demo

Experience all layouts, themes, and transitions: View Demo


Table of contents

Installation

To add @fsegurai/marked-extended-slide along with Marked.js to your package.json use the following commands.

bun install @fsegurai/marked-extended-slide marked@^17 --save

Usage

Basic Usage

Import @fsegurai/marked-extended-slide and apply it to your Marked instance as shown below.

Quick Start

Basic Concept

The slide extension requires the presentation wrapper blocks:

  • Start with ::::presentation
  • Add one or more ::::slide blocks
  • End each slide with ::::slideend
  • End the presentation with ::::presentationend

Without this wrapper syntax, content is rendered as normal Markdown.

import { marked } from 'marked';
import markedExtendedSlide from '@fsegurai/marked-extended-slide';

// or UMD script
// <script src="https://cdn.jsdelivr.net/npm/marked/lib/marked.umd.js"></script>
// <script src="https://cdn.jsdelivr.net/npm/@fsegurai/marked-extended-slide/lib/index.umd.js"></script>

marked.use(markedExtendedSlide());

// Required structural styles
import '@fsegurai/marked-extended-slide/styles/slide.css';
// Optional visual theme
import '@fsegurai/marked-extended-slide/styles/slide-theme.css';

marked.use(markedExtendedSlide({
theme: 'dark',
transition: 'slide',
showControls: true,
showProgress: true,
keyboardNavigation: true,
}));

const presentation = `
::::presentation{title="Building Modern Web Apps" author="Jane Developer" date="February 17, 2026" theme="dark"
transition="slide"}

::::slide{layout="cover" background="linear-gradient(to right, #667eea 0%, #764ba2 100%)"}

# Building Modern Web Apps

A Technical Deep Dive

**Jane Developer** | Senior Engineer
::::slideend

::::slide

## Agenda

1. Architecture Overview
2. Performance Optimization
3. Security Best Practices
4. Deployment Strategies
5. Q&A
   ::::slideend

::::presentationend
`;

const html = marked.parse(presentation);
document.getElementById('presentation-container').innerHTML = html;

This extension injects navigation script behavior for interactivity by default (injectScript: true). Import styles manually (slide.css required, slide-theme.css optional).

Runtime Behavior in SPA Frameworks

In Angular/React/Vue, slide HTML is often rendered after initial page load. The extension handles this with MutationObserver and re-initialization hooks.

  • Use injectScript: true for standard interactive behavior (recommended)
  • Avoid calling window.initPresentation() repeatedly unless you really need manual control
  • Register the extension once in app bootstrap/singleton setup

Why injectScript: false can appear blank

This is expected with the current runtime model:

  • .marked-extended-slide-slide starts hidden (opacity: 0)
  • JavaScript initialization marks one slide as .active
  • with injectScript: false, no runtime sets .active, so slides stay hidden

If you disable script injection, you must provide equivalent client-side activation logic.

Angular quick guidance (ngx-markdown)

provideMarkdown({
    markedExtensions: [
        {
            provide: MARKED_EXTENSIONS,
            useFactory: () => markedExtendedSlide({injectScript: true}),
            multi: true,
        },
    ],
});

Use global styles (styles.scss) for slide styles, not component-scoped styles.

Troubleshooting

| Symptom | Likely Cause | Recommended Fix | |------------------------------------|------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| | Slides not visible | slide.css missing or injectScript: false without manual activation | Import slide.css globally and keep injectScript: true unless you provide custom runtime | | Duplicate keyboard button | Repeated presentation initialization | Update to latest package and avoid manual repeated window.initPresentation() calls | | Overview mode feels glitchy | Duplicate listeners from repeated init | Ensure extension is registered once and avoid duplicate app bootstrap setup | | Controls visible but no navigation | DOM replaced after init | Re-render once, then call window.initPresentation() once only if needed |

Syntax & Usage

Minimal Valid Presentation

::::presentation

::::slide

# First Slide

Hello slides.
::::slideend

::::presentationend

Common Pitfalls

  • Using --- as separator without slide blocks (renders as normal markdown)
  • Missing ::::slideend or ::::presentationend
  • Not importing slide.css (structure/visibility issues)

Styling Your Presentations

This extension provides structural behavior and supports theme customization through CSS classes and variables.

Generated HTML Structure


<div class="marked-extended-slide-presentation" data-theme="dark" data-aspect-ratio="16:9" data-transition="slide">
    <div class="marked-extended-slide-controls">
        <button class="marked-extended-slide-control marked-extended-slide-prev">...</button>
        <button class="marked-extended-slide-control marked-extended-slide-next">...</button>
    </div>

    <div class="marked-extended-slide-progress">
        <div class="marked-extended-slide-progress-bar" style="width: 30%"></div>
    </div>

    <section class="marked-extended-slide-slide marked-extended-slide-layout-default">
        <div class="marked-extended-slide-content">
            <h1>Slide Title</h1>
        </div>
    </section>
</div>

CSS Classes Reference

| Class | Purpose | Element | |----------------------------------------------------------|-------------------------|---------------| | .marked-extended-slide-presentation | Main container | Container | | .marked-extended-slide-presentation[data-theme="dark"] | Theme variant | Container | | .marked-extended-slide-slide | Individual slide | Slide wrapper | | .marked-extended-slide-slide.active | Current/visible slide | Active slide | | .marked-extended-slide-layout-default | Default layout | Slide | | .marked-extended-slide-layout-cover | Cover/title layout | Slide | | .marked-extended-slide-layout-two-cols | Two-column layout | Slide | | .marked-extended-slide-layout-quote | Quote layout | Slide | | .marked-extended-slide-layout-section | Section divider | Slide | | .marked-extended-slide-content | Slide content area | Content | | .marked-extended-slide-controls | Control buttons wrapper | Nav | | .marked-extended-slide-control | Control button | Button | | .marked-extended-slide-progress | Progress bar container | Progress | | .marked-extended-slide-progress-bar | Progress bar fill | Bar | | .marked-extended-slide-slide-number | Slide counter | Number |

Base Styling Example

/* Presentation Container */
.marked-extended-slide-presentation {
    position: relative;
    width: 100%;
    height: 100vh;
    background: #1a1a1a;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    overflow: hidden;
}

/* Slides */
.marked-extended-slide-slide {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4rem;
    background: var(--slide-bg, #fff);
    color: var(--slide-text, #333);
    opacity: 0;
    transform: translateX(100%);
    transition: all 0.6s ease;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}

.marked-extended-slide-slide.active {
    opacity: 1;
    transform: translateX(0);
    z-index: 1;
}

/* Slide Content */
.marked-extended-slide-content {
    width: 100%;
    max-width: 960px;
}

/* Layout: Cover */
.marked-extended-slide-layout-cover {
    text-align: center;
}

.marked-extended-slide-layout-cover h1 {
    font-size: 3.5rem;
    margin: 0 0 1rem 0;
    line-height: 1.2;
}

/* Layout: Two Columns */
.marked-extended-slide-layout-two-cols .marked-extended-slide-content {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 3rem;
    align-items: start;
}

/* Layout: Quote */
.marked-extended-slide-layout-quote blockquote {
    font-size: 2rem;
    font-style: italic;
    border-left: 4px solid var(--slide-accent, #0066cc);
    padding-left: 2rem;
    margin: 0;
}

/* Layout: Section Divider */
.marked-extended-slide-layout-section {
    background: var(--slide-accent, #0066cc);
    color: white;
    font-size: 3rem;
    font-weight: 700;
    text-align: center;
}

/* Controls */
.marked-extended-slide-controls {
    position: absolute;
    bottom: 2rem;
    right: 2rem;
    display: flex;
    gap: 0.5rem;
    z-index: 100;
}

.marked-extended-slide-control {
    width: 48px;
    height: 48px;
    border: none;
    background: rgba(0, 0, 0, 0.6);
    color: white;
    border-radius: 50%;
    font-size: 1.5rem;
    cursor: pointer;
    transition: all 0.2s;
    backdrop-filter: blur(4px);
}

.marked-extended-slide-control:hover {
    background: rgba(0, 0, 0, 0.8);
    transform: scale(1.1);
}

/* Progress Bar */
.marked-extended-slide-progress {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: rgba(0, 0, 0, 0.3);
    z-index: 100;
}

.marked-extended-slide-progress-bar {
    height: 100%;
    background: var(--slide-accent, #0066cc);
    transition: width 0.3s ease;
}

/* Slide Number */
.marked-extended-slide-slide-number {
    position: absolute;
    bottom: 1rem;
    right: 1rem;
    font-size: 0.875rem;
    color: rgba(0, 0, 0, 0.5);
}

/* Overview Mode */
.marked-extended-slide-presentation.overview-mode .marked-extended-slide-slide {
    opacity: 0.8;
    transform: scale(0.25);
    transition: transform 0.2s, opacity 0.2s;
}

.marked-extended-slide-presentation.overview-mode .marked-extended-slide-slide:hover {
    opacity: 1;
    transform: scale(0.27);
    cursor: pointer;
}

Theme Examples

Dark Theme:

.marked-extended-slide-presentation[data-theme="dark"] {
    --slide-bg: #1a1a1a;
    --slide-text: #e0e0e0;
    --slide-accent: #4a9eff;
    --slide-heading: #ffffff;
    background: #0a0a0a;
}

Light Theme:

.marked-extended-slide-presentation[data-theme="light"] {
    --slide-bg: #ffffff;
    --slide-text: #333333;
    --slide-accent: #0066cc;
    --slide-heading: #1a1a1a;
    background: #f5f5f5;
}

Dracula Theme:

.marked-extended-slide-presentation[data-theme="dracula"] {
    --slide-bg: #282a36;
    --slide-text: #f8f8f2;
    --slide-accent: #ff79c6;
    --slide-heading: #50fa7b;
    background: #1e1f29;
}

Nord Theme:

.marked-extended-slide-presentation[data-theme="nord"] {
    --slide-bg: #2e3440;
    --slide-text: #d8dee9;
    --slide-accent: #88c0d0;
    --slide-heading: #eceff4;
    background: #242933;
}

GitHub Light Theme:

.marked-extended-slide-presentation[data-theme="github-light"] {
    --slide-bg: #ffffff;
    --slide-text: #24292e;
    --slide-accent: #0366d6;
    --slide-heading: #1b1f23;
    background: #f6f8fa;
}

Material Theme:

.marked-extended-slide-presentation[data-theme="material"] {
    --slide-bg: #263238;
    --slide-text: #cfd8dc;
    --slide-accent: #80cbc4;
    --slide-heading: #eceff1;
    background: #1e272e;
}

Cyberpunk Theme:

.marked-extended-slide-presentation[data-theme="cyberpunk"] {
    --slide-bg: #0a0e27;
    --slide-text: #00ffff;
    --slide-accent: #ff00ff;
    --slide-heading: #ffff00;
    background: #000000;
}

High Contrast Theme (Accessibility):

.marked-extended-slide-presentation[data-theme="high-contrast"] {
    --slide-bg: #000000;
    --slide-text: #ffffff;
    --slide-accent: #ffff00;
    --slide-heading: #ffffff;
    background: #000000;
}

Keyboard Navigation Styling

/* Show keyboard hint */
.marked-extended-slide-keyboard-toggle {
    position: relative;
}

.marked-extended-slide-keyboard-toggle::after {
    content: 'Keyboard: Enabled';
    position: absolute;
    bottom: 100%;
    right: 0;
    background: rgba(0, 0, 0, 0.9);
    color: white;
    padding: 0.5rem 1rem;
    border-radius: 4px;
    font-size: 0.75rem;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s;
    margin-bottom: 0.5rem;
}

.marked-extended-slide-keyboard-toggle:hover::after {
    opacity: 1;
}

/* Disabled keyboard state */
.marked-extended-slide-keyboard-toggle.disabled {
    opacity: 0.5;
}

Responsive Adjustments

@media (max-width: 768px) {
    .marked-extended-slide-slide {
        padding: 2rem;
    }

    .marked-extended-slide-layout-cover h1 {
        font-size: 2rem;
    }

    .marked-extended-slide-layout-two-cols .marked-extended-slide-content {
        grid-template-columns: 1fr;
        gap: 1.5rem;
    }

    .marked-extended-slide-controls {
        bottom: 1rem;
        right: 1rem;
    }

    .marked-extended-slide-control {
        width: 40px;
        height: 40px;
        font-size: 1.25rem;
    }
}

Print Styles

@media print {
    .marked-extended-slide-presentation {
        height: auto;
        background: white;
    }

    .marked-extended-slide-slide {
        position: relative;
        transform: none !important;
        opacity: 1 !important;
        page-break-after: always;
        background: white !important;
        color: black !important;
        box-shadow: none !important;
    }

    .marked-extended-slide-controls,
    .marked-extended-slide-progress {
        display: none !important;
    }
}

Available Themes (16 Total)

  1. default - Clean and professional
  2. light - Bright white background
  3. dark - Dark background with light text
  4. solarized-light - Solarized light palette
  5. solarized-dark - Solarized dark palette
  6. dracula - Popular Dracula theme
  7. nord - Nord color scheme
  8. monokai - Classic Monokai
  9. github-light - GitHub's light theme
  10. github-dark - GitHub's dark theme
  11. one-dark - Atom One Dark
  12. gruvbox-light - Gruvbox light variant
  13. gruvbox-dark - Gruvbox dark variant
  14. material - Material Design
  15. tokyo-night - Tokyo Night theme
  16. high-contrast - Maximum accessibility

Copy Demo Theme

For all 16 themes: slide-themes.css

Check the demo to see all themes and layouts in action.

Keyboard Controls:

  • / Space / Page Down - Next slide
  • / Page Up - Previous slide
  • Home - First slide
  • End - Last slide
  • O / Escape - Toggle overview mode
  • F - Toggle fullscreen

Programmatic API:

window.presentation.next();        // Go to next slide
window.presentation.prev();        // Go to previous slide
window.presentation.goto(5);       // Go to slide 5
window.presentation.toggleOverview(); // Toggle overview
window.presentation.getCurrentSlide(); // Get current slide index
window.presentation.getTotalSlides();  // Get total slides

Creating Slides

Wrap your deck in a presentation block and add as many ::::slide blocks as needed:

::::presentation

::::slide

# First Slide

Content here
::::slideend

::::slide

# Second Slide

More content
::::slideend

::::presentationend

Front Matter and Properties

This extension does not use YAML front matter blocks for parsing slide structure. Use inline properties instead:

Presentation-level properties:

::::presentation{title="My Presentation" author="John Doe" date="2024-02-07" theme="dark" transition="fade"}

::::slide

# First Slide

::::slideend

::::presentationend

Slide-level properties:

::::presentation

::::slide{layout="cover" background="#667eea" transition="zoom" class="custom-class" notes="Remember this point"}

# Slide Content

::::slideend

::::presentationend

Slide Layouts

The extension supports multiple built-in layouts:

  • default - Standard slide with content
  • cover - Centered title slide
  • center - Centered content
  • two-cols - Two-column layout
  • image-right - Image on the right, content on left
  • image-left - Image on the left, content on right
  • full - Full-screen content (no padding)
  • statement - Large, bold statement
  • fact - Highlight a key fact
  • quote - Styled quote layout
  • section - Section divider slide

Example:

::::presentation

::::slide{layout="two-cols"}

# Two Column Layout

Left column

Right column
::::slideend

::::presentationend

Backgrounds

Add custom backgrounds using slide properties:

Solid colors:

::::slide{background="#667eea"}

# Slide

::::slideend

Gradients:

::::slide{background="linear-gradient(to right, #667eea 0%, #764ba2 100%)"}

# Slide

::::slideend

Images:

::::slide{backgroundImage="https://example.com/image.jpg" backgroundSize="cover" backgroundPosition="center"}

# Slide

::::slideend

Transitions

Supported transition effects:

  • slide (default)
  • fade
  • slide-up
  • slide-down
  • zoom
  • none

Set globally:

marked.use(markedExtendedSlide({
    transition: 'fade',
}));

Or per slide:

::::slide{transition="zoom"}

# Zoom Slide

::::slideend

Navigation

Controls:

  • Navigation arrows appear in the bottom-right
  • Progress bar at the bottom
  • Slide numbers (optional)
  • Overview mode for slide grid

Disable controls:

marked.use(markedExtendedSlide({
    showControls: false,
    showProgress: false,
    showSlideNumbers: false,
}));

Configuration Options

| Option | Type | Default | Description | |-------------------------|------------------|---------------------------|------------------------------| | className | string | 'marked-extended-slide' | CSS class prefix | | prefixId | string | 'slide-' | ID prefix for slides | | transition | string | 'slide' | Default transition effect | | transitionDuration | string | '0.6s' | Transition duration | | defaultLayout | string | 'default' | Default slide layout | | showSlideNumbers | boolean | true | Show slide numbers | | showControls | boolean | true | Show navigation controls | | showProgress | boolean | true | Show progress bar | | keyboardNavigation | boolean | true | Enable keyboard shortcuts | | touchNavigation | boolean | true | Enable touch/swipe | | overviewMode | boolean | true | Enable overview mode | | aspectRatio | string | '16:9' | Slide aspect ratio | | theme | string | 'default' | Theme name | | template | string | null | null | Custom slide template | | containerTemplate | string | null | null | Custom container template | | customizeToken | function | null | null | Token customization function | | customizePresentation | function | null | null | Presentation customization | | injectScript | boolean | true | Auto-inject navigation JS |

Note: Import CSS/SCSS files manually.

Advanced Features

Speaker Notes:

::::slide{notes="Remember to mention the quarterly results here"}

# Q4 Results

::::slideend

Custom Classes:

::::slide{class="special-slide highlight"}

# Special Slide

::::slideend

Hide Slide Numbers:

::::slide{hideSlideNumber="true"}

# Clean Slide

::::slideend

Nested Extensions:

Slide bodies are rendered with the active Marked parser, so any registered extension can run inside a slide without special handling.

::::presentation

::::slide

# Slide with Accordion

::::accordion{title="Click to expand"}
Hidden content here
::::accordionend
::::slideend

::::slide

# Slide with Alert

> [!NOTE]
> This is an alert inside a slide
::::slideend

::::presentationend

Responsive Design

Slides automatically scale on smaller screens while maintaining aspect ratio. The extension includes print styles for PDF export.

Themes

Create custom themes by overriding CSS variables:

.marked-extended-slide-presentation[data-theme="custom"] {
    --slide-bg: #f0f0f0;
    --slide-text: #333;
    --slide-accent: #ff6b6b;
    --slide-border: #ddd;
}

Available Extensions

| Extension | Package | Version | Description | |-------------|--------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------|----------------------------------------------------------------------| | All - Bundle | @fsegurai/marked-extended-bundle | npm | Includes all extensions in a single package for easy integration | | Accordion | @fsegurai/marked-extended-accordion | npm | Add collapsible accordion sections to your markdown | | Alert | @fsegurai/marked-extended-alert | npm | Create styled alert boxes for important information | | Comments | @fsegurai/marked-extended-comments | npm | Add comment sections with author and timestamp metadata | | Embeds | @fsegurai/marked-extended-embeds | npm | Easily embed content from various platforms (YouTube, Twitter, etc.) | | Footnote | @fsegurai/marked-extended-footnote | npm | Add footnotes with automatic numbering | | Kanban | @fsegurai/marked-extended-kanban | npm | Create kanban boards with customizable columns and cards | | Lists | @fsegurai/marked-extended-lists | npm | Enhanced list formatting options | | Slide | @fsegurai/marked-extended-slide | npm | Create slide decks directly from markdown content | | Spoiler | @fsegurai/marked-extended-spoiler | npm | Hide content behind spoiler tags | | Tables | @fsegurai/marked-extended-tables | npm | Advanced table formatting with cell spanning | | Tabs | @fsegurai/marked-extended-tabs | npm | Create tabbed content sections | | Timeline | @fsegurai/marked-extended-timeline | npm | Display content in an interactive timeline format | | Typographic | @fsegurai/marked-extended-typographic | npm | Improve typography with smart quotes, dashes, and more |

Demo Application

To see all extensions in action, check out the [DEMO].

To set up the demo locally, follow the next steps:

git clone https://github.com/fsegurai/marked-extensions.git
bun install
bun start

This will serve the application locally at http://[::1]:8000.

License

Licensed under MIT.