Create CSS Transitions When Switching Between Pages – swup

Category: Animation , Javascript , Recommended | January 8, 2024
Author:gmrchk
Views Total:205 views
Official Page:Go to website
Last Update:January 8, 2024
License:MIT

Preview:

Create CSS Transitions When Switching Between Pages – swup

Description:

The swup JavaScript library lets you apply custom CSS transitions to pages when switching between them. Supports preload, page cache, and event handlers.

See also:

Table Of Contents:

How to use it:

Install the swup library.

# NPM
$ npm install swup --save

Import the swup library.

import Swup from 'swup'

Or directly load the swup file in the document.

<script src="./dist/swup.js"></script>
<!-- or from a CDN -->
<script src="https://unpkg.com/swup@3"></script>

Initialize the swup library and we’re ready to go.

const swup = new Swup()

Add the CSS ID ‘swup’ to the element you want to animate.

<main id="swup">
  Main content here
</main>

Add an animation class to the element.

<main id="swup" class="animation-class">
  Main content here
</main>

Apply your own transition effects to the page.

.animation-class {
  /* default animation rules */
}
html.is-animating .animation-class {
  /* CSS styles when animating  */
}
html.is-changing .animation-class {
  /* CSS styles when changing  */
}
html.is-leaving .animation-class {
  /* CSS styles when leaving  */
}
html.is-rendering .animation-class {
  /* CSS styles when rendering  */
}

All default config options.

const swup = new Swup({
      // when this option is enabled, swup disables browser native scroll control (sets scrollRestoration to manual) and takes over this task. 
      // This means that position of scroll on previous page(s) is not preserved (but can be implemented manually based on use case). 
      // Otherwise swup scrolls to top/#element on popstate as it does with normal browsing.
      animateHistoryBrowsing: false,
      // animation selector
      animationSelector: '[class*="transition-"]',
      // defines link elements that will trigger the transition
      linkSelector: 'a[href^="' + window.location.origin + '"]:not([data-no-swup]), a[href^="/"]:not([data-no-swup]), a[href^="#"]:not([data-no-swup])',
      //  pass in navigate to treat these links like any other link and perform a regular navigation.
      linkToSelf: 'scroll',
      // stores previously loaded contents of the pages in memory
      cache: true,
      // default container(s)
      containers: ['#swup'],
      // request headers
      requestHeaders: {
        'X-Requested-With': 'swup',
        Accept: 'text/html, application/xhtml+xml'
      },
      // enable/disable plugins
      // see below
      plugins: [],
      // skips popState handling when using other tools manipulating the browser history
      skipPopStateHandling: function skipPopStateHandling(event) {
        return !(event.state && event.state.source === 'swup');
      },
      // allows ignoring specific visits through a callback
      ignoreVisit: (href, { el } = {}) => el?.closest('[data-no-swup]'),
      // provides a way of rewriting URLs before swup will attempt to load them
      resolveUrl: (url) => {
        if (url.startsWith('/projects/?')) {
          return '/projects/';
        }
        return url;
      }
})

Events.

swup.on('animationInDone', () => {
  //  do something
});
swup.on('animationInStart', () => {
  //  do something
});
swup.on('animationOutDone', () => {
  //  do something
});
swup.on('animationOutStart', () => {
  //  do something
});
swup.on('animationSkipped', () => {
  //  do something
});
swup.on('clickLink', () => {
  //  do something
});
swup.on('contentReplaced', () => {
  //  do something
});
swup.on('disabled', () => {
  //  do something
});
swup.on('enabled', () => {
  //  do something
});
swup.on('hoverLink', () => {
  //  do something
});
swup.on('openPageInNewTab', () => {
  //  do something
});
swup.on('pageLoaded', () => {
  //  do something
});
swup.on('pagePreloaded', () => {
  //  do something
});
swup.on('pageRetrievedFromCache', () => {
  //  do something
});
swup.on('pageView', () => {
  //  do something
});
swup.on('popState', () => {
  //  do something
});
swup.on('pageLoaded', () => {
  //  do something
});
swup.on('samePage', () => {
  //  do something
});
swup.on('samePageWithHash', () => {
  //  do something
});
swup.on('transitionStart', () => {
  //  do something
});
swup.on('transitionEnd', () => {
  //  do something
});
swup.on('willReplaceContent', () => {
  //  do something
});

Official plugins.

// register plugins
const swup = new Swup({
      plugins: [new PluginName()]
});
// Accessibility Plugin
npm install @swup/a11y-plugin
import SwupA11yPlugin from '@swup/a11y-plugin';
<script src="./dist/SwupA11yPlugin.js"></script>
SwupA11yPlugin({
  contentSelector: 'main',
  headingSelector: 'h1, h2, [role=heading]',
  announcementTemplate: 'Navigated to: {title}',
  urlTemplate: 'New page at {url}'
})
// Body Class plugin
npm install @swup/body-class-plugin
import SwupBodyClassPlugin from '@swup/body-class-plugin';
<script src="./dist/SwupBodyClassPlugin.js"></script>
SwupBodyClassPlugin({
  prefix: ''
})
// Custom Payload Plugin
npm install @swup/custom-payload-plugin
import SwupCustomPayloadPlugin from '@swup/custom-payload-plugin';
<script src="./dist/SwupCustomPayloadPlugin.js"></script>
SwupCustomPayloadPlugin({
  generatePageObject: (request) => {  
    // receives request object created by swup which contains server response
    // parse data from request here and prepare it for return
    return {
      title,  // required - title of page
      blocks, // required - containers on page in correct order (as marked by [data-swup] attributes in DOM)
      pageClass, // not requered - class of body element (but might be required by some plugin like Body Class plugin)
      originalContent,    // not required - whole page html content (but might be required by some plugin) 
    };
  }
})
// Debug plugin
npm install @swup/debug-plugin
import SwupDebugPlugin from '@swup/debug-plugin';
<script src="./dist/SwupDebugPlugin.js"></script>
SwupDebugPlugin({
  globalInstance: true
})
// Forms plugin (send forms via swup)
npm install @swup/forms-plugin
import SwupFormsPlugin from '@swup/forms-plugin';
<script src="./dist/SwupFormsPlugin.js"></script>
SwupFormsPlugin({
  formSelector: 'form[data-swup-form]'
});
swup.on('submitForm', e => console.log(e));
// Google Analytics plugin
npm install @swup/ga-plugin
import SwupGaPlugin from '@swup/ga-plugin';
<script src="./dist/SwupGaPlugin.js"></script>
wupGaPlugin({
  gaMeasurementId: GA_MEASUREMENT_ID,
})
// Gia framework plugin
npm install @swup/gia-plugin
import SwupGiaPlugin from '@swup/gia-plugin';
<script src="./dist/SwupGiaPlugin.js"></script>
SwupGiaPlugin({
  components: components,
  firstLoad: true,
  log: false,
})
// Google Tag Manager Plugin 
npm install @swup/gtm-plugin
import SwupGtmPlugin from '@swup/gtm-plugin';
<script src="./dist/SwupGtmPlugin.js"></script>
// Head Plugin (replace the contents of head tag when the content of the page is replaced)
npm install @swup/head-plugin
import SwupHeadPlugin from '@swup/head-plugin';
<script src="./dist/SwupHeadPlugin.js"></script>
SwupHeadPlugin({
  persistAssets: true
  persistTags: true,
  // persistTags: 'style[data-keep-style]',
  // persistTags: (tag) => tag.children.length > 1
})
// JS plugin (enable the use of JavaScript for timing and animations)
npm install @swup/js-plugin
import SwupJsPlugin from '@swup/js-plugin';
<script src="./dist/SwupJsPlugin.js"></script>
SwupJsPlugin([
  {
    from: '(.*)',
    to: '(.*)',
    in: (next, infos) => {
      document.querySelector('#swup').style.opacity = 0;
      gsap.to(document.querySelector('#swup'), {
        duration: 0.5,
        opacity: 1,
        onComplete: next
      });
    },
    out: (next, infos) => {
      document.querySelector('#swup').style.opacity = 1;
      gsap.to(document.querySelector('#swup'), 0.5, {
        duration: 0.5,
        opacity: 0,
        onComplete: next
      });
    }
  }
])
// Laravel Livewire Plugin
npm install @swup/livewire-plugin
import SwupLivewirePlugin from '@swup/livewire-plugin';
<script src="./dist/SwupLivewirePlugin.js"></script>
// Matomo Plugin
npm install @swup/matomo-plugin
import SwupMatomoPlugin from '@swup/matomo-plugin';
<script src="./dist/SwupMatomoPlugin.js"></script>
// Preload plugin
npm install @swup/preload-plugin
import SwupPreloadPlugin from '@swup/preload-plugin';
<script src="https://unpkg.com/@swup/preload-plugin@2"></script>
const preloadPromise = swup.preloadPage('/path/to/my/page.html');
swup.preloadPages();
swup.on('pagePreloaded', (page) => console.log('preloaded:' page));
swup.on('hoverLink', (event) => console.log('link hovered:', event));
// Progress Bar Plugin
npm install @swup/progress-plugin
import SwupProgressPlugin from '@swup/progress-plugin';
<script src="./dist/SwupProgressPlugin.js"></script>
SwupProgressPlugin({
    className: 'swup-progress-bar',
    transition: 300,
    delay: 300,
    initialValue: 0.25,
    hideImmediately: true
})
// Route Name Plugin
npm install @swup/route-name-plugin
import SwupRouteNamePlugin from '@swup/route-name-plugin';
<script src="./dist/SwupRouteNamePlugin.js"></script>
SwupRouteNamePlugin({
  routes: [
    { name: 'home', path: '/:lang?' },
    { name: 'projects', path: '/:lang/projects' },
    { name: 'project', path: '/:lang/project/:slug' },
    { name: 'any', path: '(.*)' }
  ],
  unknownName: 'unknown',
  pathToRegexpOptions: {}
})
// Scripts Plugin (re-run any scripts in head/body on swups contentReplaced even)
npm install @swup/scripts-plugin
import SwupScriptsPlugin from '@swup/scripts-plugin';
<script src="./dist/SwupScriptsPlugin.js"></script>
SwupScriptsPlugin({
  head: true,
  body: true,
  optin: false
});
// Scroll plugin
npm install @swup/scroll-plugin
import SwupScrollPlugin from '@swup/scroll-plugin';
<script src="https://unpkg.com/@swup/scroll-plugin@2"></script>
SwupScrollPlugin({
  doScrollingRightAway: false,
  animateScroll: {
    betweenPages: true,
    samePageWithHash: true,
    samePage: true
  },
  scrollFriction: 0.3,
  scrollAcceleration: 0.04,
  getAnchorElement: null,
  offset: 0,
  scrollContainers: `[data-swup-scroll-container]`,
  shouldResetScrollPosition: htmlAnchorElement => true
})
swup.scrollTo(2000, true);
swup.on('scrollStart', () => {
  console.log('Swup started scrolling');
});
swup.on('scrollDone', () => {
  console.log('Swup finished scrolling');
});

Themes

// register themes
const swup = new Swup({
      plugins: [new ThemeName()]
});
// Fade Theme
npm install @swup/fade-theme
import SwupFadeTheme from '@swup/fade-theme';
<script src="./dist/SwupFadeTheme.js"></script>
SwupFadeTheme({
  mainElement: "#swup"
})
// Slide Theme
npm install @swup/slide-theme
import SwupSlideTheme from '@swup/slide-theme';
<script src="./dist/SwupSlideTheme.js"></script>
SwupSlideTheme({
  mainElement: "#swup",
  reversed: false
})
// Overlay Theme
npm install @swup/overlay-theme
import SwupOverlayTheme from '@swup/overlay-theme';
<script src="./dist/SwupOverlayTheme.js"></script>
SwupOverlayTheme({
  color: '#2D2E82',
  duration: 600,
  direction: 'to-right',
});

Changelog:

v4.5.1 (01/08/2023)

  • Wait with transition class mutations when pausing before content:replace
  • Ignore errors in user hooks

v4.5.0 (12/02/2023)

  • Support View Transitions API in new native mode
  • Handle rapid link clicks to achieve smooth transitions
  • Abort superseded visits with new visit:abort hook

v4.4.4 (11/17/2023)

  • Dispatch DOM event swup:any any time a hook is run
  • Allow listening to DOM events from the window (previously, only document was receiving swup events)
  • Improve working with DOM events in TypeScript by exporting a new type SwupEvent

v4.4.3 (11/16/2023)

  • Improve compatibility with older Safari versions

v4.4.2 (09/28/2023)

  • Export types for hook handlers and return values

v4.4.1 (09/25/2023)

  • Fix multiple rapid clicks on links

v4.4.0 (09/19/2023)

  • Enable experimental ViewTransition support
  • Extend test coverage to all major browsers
  • Add request timeout option

v4.3.4 (08/25/2023)

  • Add unique id to visit object

v4.3.3 (08/22/2023)

  • Restore history index on reload

v4.3.2 (08/20/2023)

  • Update history entry on links to the current page

v4.3.1 (08/17/2023)

  • Improve scroll restoration on history visits

v4.3.0 (08/16/2023)

  • Persist elements across page loads using data-swup-persist
  • Add visit.cache key to control cache behavior
  • Enforce parameter and return types of hook handlers

v4.2.0 (08/09/2023)

  • Add option linkToSelf to control behavior for links to the current page
  • Don’t create history records for repeated visits to the current page
  • Allow updating visit.to.hash and visit.scroll.target separately

v4.1.0 (07/30/2023)

  • Prevent unintentional cache mutation
  • Use recommended order for package.json “exports”
  • Infer element type from delegate selector

v4.0.1 (07/28/2023)

  • Export additional types to allow augmentation from plugins

v4.0.0 (07/26/2023)

  • Built-in scroll support
  • New hook system for customizing the page load lifecycle
  • Visit object for controlling the transition process
  • Animation scope: add animation classes to html element or to containers
  • Easier customization of official themes
  • Allow pruning cache entries
  • Hooks replace events: swup.hooks.on()
  • Use the visit argument in hooks instead of swup.transition
  • Container selectors now only match one single element per selector
  • Custom animation attribute renamed to data-swup-animation
  • Swup no longer adds data-swup attributes to containers
  • Navigation method renamed: swup.navigate()
  • Simplified cache API: cache.set()
  • Support for custom payload formats was dropped

v3.1.1 (06/24/2023)

  • Accept #top as a special scroll target

v3.1.0 (06/13/2023)

  • Allow replacing the current history entry

v3.0.8 (06/05/2023)

  • Create smaller bundle for modern browsers
  • Make warning about missing transitions less strict

v3.0.7 (05/26/2023)

  • Update event delegation library
  • Fix edge case in detecting transition events
  • Improve selection of scroll anchor targets

v3.0.6 (04/07/2023)

  • update

v3.0.5 (03/02/2023)

  • Ensure correct Referer request header

v3.0.4 (01/30/2023)

  • Specify exact types for each type of event handler
  • Update package version

v3.0.3 (01/27/2023)

  • Use shared browserslist config

v3.0.2 (01/21/2023)

  • Make sure ignoreVisit option is called when visiting pages programmatically

v3.0.1 (01/20/2023)

  • Fix: remove origin from ignoreVisit parameter

v3.0.0 (01/19/2023)

  • Support CSS animations and keyframes
  • Allow ignoring visits via callback function
  • Export native ESM modules
  • Smaller bundle size for modern browsers: 4.5 kB

v2.0.19 (08/24/2022)

  • Disable caching of initial page to avoid caching modified DOM
  • Gracefully handle missing document title
  • Force-reload if next page has no swup containers
  • Remove all reliance on global window.swup instance

v2.0.18 (08/10/2022)

  • Fixes the buggy behavior when navigating rapidly between pages

v2.0.17 (08/02/2022)

  • Gracefully handle missing transitions on container
  • Warn about missing container
  • Scope transition selector to body
  • Normalize cache paths

v2.0.16 (07/01/2022)

  • Improve handling of scroll anchors with special characters

v2.0.15 (06/15/2022)

  • Update dependencies

v2.0.14 (12/27/2020)

  • Bugfix

v2.0.13 (12/07/2020)

  • update patch version

v2.0.12 (11/30/2020)

  • fix bug where animateHistoryBrowsing option was ignored for OUT animations

v2.0.11 (07/09/2020)

  • update version

v2.0.9 (02/26/2020)

  • removed destroy of mouseover listener as it was moved to the preload plugin

v2.0.8 (11/01/2019)

  • fix problem when ‘<body’ string is present in DOM

v2.0.5 (07/15/2019)

  • updated

v2.0.4 (05/31/2019)

  • fix wrong uppercase/lowercase letters in imports

v2.0.2 (05/27/2019)

  • major update

v1.9.0 (01/07/2019)

  • make preloadPage method return Promise

v1.7.18 (01/07/2018)

  • fix querySelectorAll issue in form handler and destroy method

v1.7.17 (12/17/2018)

  • fix swup getting stuck by errors inside of handlers defined with on method

You Might Be Interested In:


2 thoughts on “Create CSS Transitions When Switching Between Pages – swup

Leave a Reply