The letter A styled as Alchemists logo. lchemists
Published May 24, 2026 Updated September 22, 2026
htmx Slide Icon

htmx Slide

0.8.0

This library is a htmx extension for rendering slides.

Features

  • Renders slides with silky smooth CSS View Transitions.

  • Provides customizable slide transitions.

  • Provides full screen toggling of your presentation.

  • Provides keyboard shortcuts.

  • Works with seamlessly with dynamically or statically generated web sites.

Screencasts

Requirements

  1. htmx.

  2. Node (optional, for development).

  3. Ruby (optional, for development).

  4. entr (optional, for development).

Setup

The following assumes you are already using htmx and have it configured in the same manner as documented in this setup section.

To load CSS and JavaScript, add the following to your page:

<link href="https://unpkg.com/htmx-slide@latest/build/style.css" rel="stylesheet">

<script src="https://unpkg.com/htmx-slide@latest"
        integrity="sha384-wqhWD7RgQ3amBmpZ0soDOU6KHATp+GRksh5Y47N/vP3YYyNgaQoipBLP/Qn511zP"
        crossorigin="anonymous"
        defer>
</script>

To use via Import Maps, add the following to your layout:

<link href="https://unpkg.com/htmx-slide@latest/build/style.css" rel="stylesheet">

<script type="importmap">
  {
    "imports": {
      "htmx-slide": "https://unpkg.com/htmx-slide@latest"
    }
  }
</script>

<script type="module">
  import "htmx-slide";
</script>

To install via NPM, run:

npm install htmx-slide

Once the library is installed, you only need to import it:

import "htmx-slide/build/style.css";
import "htmx-slide";

Usage

To use, add a top-level element (section in this case) where you enable the slide extension. Once the extension has been enabled, you can then add your view port, progress bar, and actions. Example:

<section class="htmx-slide">
  <div class="container">
    <div class="viewport">
      <img src="one.svg"
           alt="One"
           class="slide"
           width="960"
           height="540"
           data-transitions-forward="push"
           data-transitions-backward="wipe">
    </div>

    <progress class="progress" value="0" max="4"></progress>

    <div class="actions">
      <a href="_five.html"
         class="action"
         data-direction="backward"
         hx-get="_five.html"
         hx-trigger="click, keyup[key == 'ArrowLeft'] from:body"
         hx-push_url="true">
        Previous
      </a>

      <span class="status">1 of 5</span>

      <a href="_two.html"
         class="action"
         data-direction="forward"
         hx-get="_two.html"
         hx-trigger="click, keyup[key == 'ArrowRight'] from:body"
         hx-push_url="true">
        Next
      </a>

      <button data-fullscreen-trigger>[ ]</button>
    </div>
  </div>
</section>

The above is the minimum to load the extension, the initial slide, and navigate between slides. Here’s the breakdown:

  • section (required): The section element provides a semantic element to encapsulate all functionality and supply the minimum attributes. You’re not limited to the section element as any valid HTML element would work for your top level element.

    • class (optional): Provides a default style for the extension. If you don’t want any styling then you can remove along with the associated style.css. The style.css is compiled from the style sheets located in the lib/stylesheets of this project. If you need a detailed breakdown on how CSS View Transitions and key frames work, check out the htmx View Transitions article to learn more.

  • .container (required): Ensures the view port, progress bar, and associated actions don’t expand the width of your slides.

  • .viewport (required): Ensures contents of this element can be toggled via the Fullscreen API.

  • .slide (required): Ensures your slide can be updated with a new slide based on the direction you are going.

  • .progress (optional): Provides real-time progress. Delete if not desired.

  • .actions (required): Ensures you can navigate to the previous, next, first, and last slide. You can add or remove actions as desired. The above shows what’s possible. When using action links, use the following attributes:

    • .action (optional): Allows you to style the action if desired.

    • data-direction (required): Ensures this extension knows which direction to transition the slide. Valid values are: forward or backward.

    • hx-get (required): Requests the next slide.

    • hx-trigger(required): Triggers the action. Feel free to customize keyboard short behavior as desired.

    • hx-push_url (optional): Ensures your browser history is updated so back and forward navigation works.

  • data-fullscreen-trigger (optional): Triggers full screen mode. The value is meant to be empty and any value supplied is ignored. You can, optionally, add a data-fullscreen-target with any valid CSS selector in case you want to target a different element for full screen. The default is: .viewport.

When building your implementation, the above shows the initial page to render. All subsequent pages only need to be HTML partials which have the elements shown in the .container as those are the only elements that need to change upon each HTTP GET request.

Configuration

In addition to the above, you can configure the extension globally or per element. The following details each.

Defaults

This extensions is configured with the following defaults:

DEFAULTS = {
  slide: ".slide",
  transitions: {
    forward: "push",
    backward: "push"
  },
  fullscreen: {
    key: "f",
    trigger: "[data-fullscreen-trigger]",
    target: ".viewport"
  }
};

Each is key is described as follows:

  • slide: Defines the slide selector. This can be any valid CSS selector.

  • transitions: Defines the transitions.

    • forward: Defines the forward transition.

    • backward: Defines the backward transition.

  • fullscreen: Defines fullscreen behavior.

    • key: Defines the keyboard shortcut to toggle full screen mode.

    • trigger: Defines the trigger selector of the element that will toggle full screen mode. This can be any valid CSS selector.

    • target: Defines the full screen target selector for which will enlarged in full screen mode.

Globals

You can override the defaults using HCON notation as follows:

<meta name="htmx-config"
      content="slide.slide:.slide
               slide.fullscreen.forward:push
               slide.fullscreen.backward:push
               slide.fullscreen.key:k
               slide.fullscreen.trigger:[data-fullscreen-trigger]
               slide.fullscreen.target:.viewport">

With the above, you’ll notice the global configuration is identical to the DEFAULTS. This is where you would customize as desired. At the moment, all keys must be represented even if you only customize a few of them.

Elements

You can also customize behavior by specific element using data attributes. For example, to change transitions, apply the following attributes to your slide (img) element:

data-transitions-forward="push"
data-transitions-backward="push"

The above gives you fine level control over the behavior of each slide instead of inheriting the default or global configuration and is a powerful way to keep your presentation interesting with different transitions.

You can also change full screen behavior by editing the element (button) that toggles full screen mode as follows:

data-fullscreen-target=".viewport"

Precedence

The configuration is dynamically computed based on global and per element customization with the first in the following list having the most specificity followed by least specificity:

  1. Elements

  2. Globals

  3. Defaults

Keyframes

Keyframes provide the low level animation sequences for use in your view transitions (see below). The source for these can be found in the lib/stylesheets/keyframes.css file which is included when you import the htmx-slide/build/style.css as described Setup section above.

Each keyframe uses the htmx-slide-* prefix but feel free to add your own and link them to your own view transitions.

View Transitions

View transitions (i.e. ::view-transition-old, ::view-transition-new) are built atop the keyframes and are what make the slide transitions possible. The source for these can be found in the lib/stylesheets/view_transitions.css file which is included when you import the htmx-slide/build/style.css as described Setup section above.

Several view transitions are provided for you:

  • Curtain

  • Iris

  • Push (default)

  • Scale

  • Wipe

You can customize each slide’s transition, as mentioned in the Configuration section, by using the following data attributes on the extension element or the slide element. Example:

  • data-transitions-forward="iris": Uses the iris transition when moving forward to the next slide.

  • data-transitions-backward="scale": Uses the scale transition when moving backward to the next slide.

Each view transition name uses the htmx-slide-<name>-forward prefix. You can create and use your own transitions by using the same format as long as your name is unique and doesn’t conflict with the provided transitions. Once your custom view transition is ready, use the name of your transition via the data-transitions-* attributes to enable.

Partials

All of your partials needs to be wrapped within the hx-partial tag. You can always add more partials and standard HTML elements as you like but the following detail what is possible:

Slide

This is your most critical partial which informs htmx how to swap in and transition your new slide. Use of transition:true is important for enabling CSS View Transitions. Example:

<hx-partial hx-target=".slide" hx-swap="outerHTML transition:true">
  <img src="one.svg"
       alt="One"
       class="slide"
       width="960"
       height="540"
       data-transitions-forward="push"
       data-transitions-backward="wipe">
</hx-partial>

Progress

As mentioned earlier this is optional but handy for providing a clear visual indication of where you are in your presentation. Example:

<hx-partial hx-target=".progress" hx-swap="outerHTML">
  <progress class="progress" value="0" max="4"></progress>
</hx-partial>

Actions

You are not limited to previous and next actions as mentioned earlier because you can add as many as you deem necessary. For example, the following shows how to use previous, next, first, and last actions for navigation.

With First and Last Actions
<hx-partial hx-target=".actions" hx-swap="outerHTML">
  <div class="actions">
    <a href="_five.html"
       class="action"
       data-direction="backward"
       hx-get="_five.html"
       hx-trigger="click, keyup[key == 'ArrowLeft'] from:body"
       hx-push_url="true">
      Previous
    </a>

    <span class="status">1 of 5</span>

    <a href="_two.html"
       class="action"
       data-direction="forward"
       hx-get="_two.html"
       hx-trigger="click, keyup[key == 'ArrowRight'] from:body"
       hx-push_url="true">
      Next
    </a>

    <a href="_one.html"
       class="action"
       data-direction="backward"
       hx-get="_one.html"
       hx-trigger="click, keyup[event.code == 'BracketLeft'] from:body"
       hx-push_url="true">
      First
    </a>

    <button data-fullscreen-trigger>[ ]</button>

    <a href="_five.html"
       class="action"
       data-direction="forward"
       hx-get="_five.html"
       hx-trigger="click, keyup[event.code == 'BracketRight'] from:body"
       hx-push_url="true">
      Last
    </a>
  </div>
</hx-partial>

As long as your actions are defined within the .actions element and wrapped within a hx-partial element, this extension will swap them in properly.

Examples

Should you need real-word examples of this extension in production use, check out the following:

  • Talks: A collection of talks given at past presentations.

  • Terminus: A web server for ePaper devices. Each playlist uses this extension for viewing screens rendered on your ePaper devices.

Development

To contribute, run:

git clone https://github.com/bkuhlmann/htmx-slide
cd htmx-slide
bin/setup

To build, run:

bin/build

To view the interactive demonstration, run:

bin/demo
open http://localhost:3030

Any changes to source code will automatically rebuild and reload the demonstration.

Tests

To test, run:

bin/rake

Deployment

To deploy, follow these steps:

  1. Ensure you are on the main branch.

  2. Ensure you’ve updated the CITATION.cff and package.json with new version and committed the changes.

  3. Run the following:

bin/build
bin/publish

Credits