swup swup Hooks
GitHub swup on GitHub

Hooks

Lifecycle hooks allow triggering custom code at each step of the page transition process. Read on to learn about registering handlers or jump straight to the list of available hooks.

Registering handlers

You can register handlers on swup's hooks registry. All handlers receive the visit object with information about the current visit as their first argument.

swup.hooks.on('page:view', (visit) => {
  console.log('New page loaded:', visit.to.url);
});
swup.hooks.on('page:view', (visit) => {
  console.log('New page loaded:', visit.to.url);
});

Handler options

Pass in an options object to customize how a handler is invoked.

once

Execute the handler once, then remove it.

swup.hooks.on('page:view', () => {}, { once: true });
swup.hooks.on('page:view', () => {}, { once: true });

before

Execute the handler before the internal default handler.

swup.hooks.on('content:replace', () => {}, { before: true });
swup.hooks.on('content:replace', () => {}, { before: true });

priority

Influence the order in which this handler is run in relation to other handlers for the same hook, regardless of order of registration. The default priority is 0 — negative values make the handler execute earlier, positive values make it execute later.

// Execute before other handlers
swup.hooks.on('visit:start', () => {}, { priority: -100 });

// Execute after other handlers
swup.hooks.on('visit:start', () => {}, { priority: 100 });
// Execute before other handlers
swup.hooks.on('visit:start', () => {}, { priority: -100 });

// Execute after other handlers
swup.hooks.on('visit:start', () => {}, { priority: 100 });

Shortcuts

There are shortcuts available for common handler options:

swup.hooks.once('page:view', () => {}); // once: true
swup.hooks.before('content:replace', () => {}); // before: true
swup.hooks.once('page:view', () => {}); // once: true
swup.hooks.before('content:replace', () => {}); // before: true

Pausing execution

Swup will await Promises returned from handlers, allowing you to pause execution.

// Delay the start of the page transition by 1 second
swup.hooks.on('visit:start', () => {
  return new Promise((res) => setTimeout(res, 1000));
});
// Delay the start of the page transition by 1 second
swup.hooks.on('visit:start', () => {
  return new Promise((res) => setTimeout(res, 1000));
});

This means that async/await handlers are supported as well:

// Wait for a custom function before starting the transition
swup.hooks.on('visit:start', async () => {
  await myCustomFunction();
});
// Wait for a custom function before starting the transition
swup.hooks.on('visit:start', async () => {
  await myCustomFunction();
});

Removing handlers

Remove a previously registered handler by passing in the function to remove.

const handler = () => console.log('New page loaded');

// Register a handler
swup.hooks.on('page:view', handler);

// Remove it again later
swup.hooks.off('page:view', handler);
const handler = () => console.log('New page loaded');

// Register a handler
swup.hooks.on('page:view', handler);

// Remove it again later
swup.hooks.off('page:view', handler);

List of hooks

The following hooks are exposed by swup and can be listened to. Refer to the lifecycle diagram for a visual overview of when the most important hooks are called. Install the Debug Plugin to log triggered hooks to the browser console as they are happening.

Hook name Description
animation:out:start Current content starts animating out. Class .is-animating is added.
animation:out:await Swup waits for CSS animations to finish before replacing the content.
animation:out:end Current content finishes animating out. Content is not yet replaced.
animation:in:start New content starts animating in. Class .is-animating is removed.
animation:in:await Swup waits for CSS animations to finish before finishing the visit.
animation:in:end New content finishes animating out.
animation:skip Page will load at once without animations, e.g. on history navigation.
cache:set Page is saved to the cache.
cache:clear The cache is cleared completely.
content:replace The old content of the page is replaced by the new content.
content:scroll The scroll position is reset after replacing the content.
enable Swup instance is created.
disable Swup instance is disabled.
fetch:error Fetch request is rejected because of a server error.
fetch:request Fetch request is sent.
fetch:timeout Fetch request has timed out.
history:popstate History navigation is started: back/forward button was pressed.
page:load Page is loaded from cache or via fetch request.
page:view New content is visible after replacing the content.
scroll:top Scroll to the top of the page.
scroll:anchor Scroll to an anchor on the current page.
visit:start Visit started: transition to a new page begins.
visit:end Visit ended: all content is replaced, animations have finished.
visit:abort Visit aborted: a new link was clicked before the current transition has finished.

Examples

Trigger analytics page views

swup.hooks.on('page:view', () => {
  ga('set', 'title', document.title);
  ga('set', 'page', window.location.pathname);
  ga('send', 'pageview');
});
swup.hooks.on('page:view', () => {
  ga('set', 'title', document.title);
  ga('set', 'page', window.location.pathname);
  ga('send', 'pageview');
});

Initialize new components on the page

swup.hooks.on('page:view', () => {
  if (document.querySelector('#carousel')) {
    const carousel = new Carousel('#carousel');
  }
});
swup.hooks.on('page:view', () => {
  if (document.querySelector('#carousel')) {
    const carousel = new Carousel('#carousel');
  }
});

Display loading indicator during transitions

swup.hooks.on('animation:out:start', () => {
  document.querySelector('#loader').hidden = false;
});
swup.hooks.on('animation:in:end', () => {
  document.querySelector('#loader').hidden = true;
});
swup.hooks.on('animation:out:start', () => {
  document.querySelector('#loader').hidden = false;
});
swup.hooks.on('animation:in:end', () => {
  document.querySelector('#loader').hidden = true;
});

Set all hook handlers at once

When creating a swup instance, you can register all your hook handlers at once by passing a keyed object into the instance options.

const swup = new Swup({
  hooks: {
    'visit:start': () => console.log('starting visit'),
    'page:load': () => console.log('loaded page'),
    'visit:end': () => console.log('finished visit')
  }
})
const swup = new Swup({
  hooks: {
    'visit:start': () => console.log('starting visit'),
    'page:load': () => console.log('loaded page'),
    'visit:end': () => console.log('finished visit')
  }
})

Hook handler options like once or before can be set by appending them to the hook name, separated by a dot: content:replace.before, fetch:error.once, etc.

const swup = new Swup({
  hooks: {
    'visit:start.once': () => console.log('triggers once'),
    'content:replace.before': () => console.log('triggers before hook')
  }
})
const swup = new Swup({
  hooks: {
    'visit:start.once': () => console.log('triggers once'),
    'content:replace.before': () => console.log('triggers before hook')
  }
})

DOM events

All hooks are also triggered on the document with a swup: prefix. They receive the hook name and the visit object inside the detail key of the event.

document.addEventListener('swup:page:view', ({ detail: { visit } }) => {
  console.log('Going to', visit.to.url);
});
document.addEventListener('swup:page:view', ({ detail: { visit } }) => {
  console.log('Going to', visit.to.url);
});