smoothState.js is a jQuery plugin that progressively enhances page loads to give us control over page transitions. If the user's browser doesn't have the required features, smoothState.js fades into the background and never runs.

Below are some cool sites built with smoothState.js. Feel free to submit a pull request with your own site, or tweet me with a link.
If you need a little help implementing smoothState there are a couple things you could do to get some support:
Please avoid creating a Github issue with personal support requests, to keep the tracker clear for bugs and pull requests.
Imagine, for a second, how disorienting it would be if touching a doorknob teleported you to the other side of the door. Navigating the web feels like using a teleporting doorknob. Layouts change, elements rearrange or disappear, and it takes time for the user to adjust. Smooth transitions reduce the effort it takes for users to get settled into a new environment.
Javascript SPA frameworks, sometimes referred to as MVC frameworks, are a common way to solve this issue. These frameworks often lose the benefits of unobtrusive code. Writing unobtrusive javascript gives us more resilience to errors, and improved performance and accessibility.
smoothState.js provides hooks that can be used to choreograph how elements enter and exit the page during navigation. It uses the time the animations are running to fetch content via AJAX to inject into the page.
smoothState.js doesn't dictate how things on the page should be animated. It supports CSS animations, as well as JS animation libraries like velocity.js.
The project's main goal is to allow developers to add page transitions without having to add any logic to the backend. We keep things unobtrusive at all times.
smoothState.js initializes on containers, not links. Think of a container as a small window object embedded in the page.
id set - a unique hook to tell us what to update on the pageThese requirements makes the website resilient, since it smoothState.js can abort and simply redirect the user if an error occurs. Making each link return a full page also ensures that pages are created with progressive enhancement in mind.
All we need to do to get started is:
#main and include some links inside of it$('#main').smoothState()$(function() {
$('#main').smoothState();
});
By default, smoothState.js will:
smoothState.js will not add page transitions to pages. You'll need to define the animations you want to run using the hooks smoothState.js provides.
onBefore - Runs before a page load has been startedonStart - Runs once a page load has been activatedonProgress - Runs if the page request is still pending and the onStart animations have finishedonReady - Run once the requested content is ready to be injected into the page and the previous animations have finishedonAfter - Runs after the new content has been injected into the page and all animations are completesmoothState.js provides some options that allow customization of the plugin's functionality. The default options are overridden by passing an object into the smoothState function.
$(function(){
'use strict';
var options = {
prefetch: true,
cacheLength: 2,
onStart: {
duration: 250, // Duration of our animation
render: function ($container) {
// Add your CSS animation reversing class
$container.addClass('is-exiting');
// Restart your animation
smoothState.restartCSSAnimations();
}
},
onReady: {
duration: 0,
render: function ($container, $newContent) {
// Remove your CSS animation reversing class
$container.removeClass('is-exiting');
// Inject the new content
$container.html($newContent);
}
}
},
smoothState = $('#main').smoothState(options).data('smoothState');
});
debugIf set to true, smoothState.js will log useful debug information to the console, instead of aborting. For example, instead of redirecting the user to a page on an error, it might log:
No element with an id of “#main” in response from “/about.html”.
// Default
$('#main').smoothState({ debug: false });
anchorsA jQuery selector specifying which anchors within the smoothState element should be bound.
// Default
$('#main').smoothState({ anchors: 'a' });
hrefRegexA regular expression to specify which anchor with a specific href property based on the regex smoothState should bind to. If empty, every href will be permitted.
// Default
$('#main').smoothState({ hrefRegex: '' });
formsA jQuery selector specifying which forms within the smoothState element should be bound.
// Default
$('#main').smoothState({ forms: 'form' });
allowFormCachingControls whether or not form submission responses are preserved in the cache. If set to true, smoothState will store form responses in the cache. This should be set to false unless you understand how caching form results will affect your website's behaviour very well.
// Default
$('#main').smoothState({ allowFormCaching: false });
repeatDelayThe minimum number of milliseconds between click/submit events. User events ignored beyond this rate are ignored. This can be used to ignore double-clicks so that the user's browser history won't become cluttered by incompleted page loads.
// Default
$('#main').smoothState({ repeatDelay: 500 });
blacklistA jQuery selector specifying which elements within the smoothState element should be ignored. This includes both form and anchor elements.
// Default
$('#main').smoothState({ blacklist: '.no-smoothState' });
prefetchThere is a 200ms to 300ms delay between the time that a user hovers over a link and the time they click it. On touch screens, the delay between the touchstart and touchend is even greater. If the prefetch option is set to true, smoothState.js will begin to preload the contents of the URL during that delay. This technique will increase the perceived performance of the site.
// Default
$('#main').smoothState({ prefetch: false });
prefetchOnThe name of the events to listen to from anchors when prefetching.
// Default
$('#main').smoothState({ prefetchOn: 'mouseover touchstart' });
If you would like to throttle the prefetch, do so by firing custom events.
Libraries like @tristen's hoverintent can be used to throttle prefetching based on the user's intent, by triggering a custom intent event. To use it with smoothState.js, set intent as the prefetchOn option.
$('#main').smoothState({ prefetchOn: 'intent' });
Or, for the opposite effect, use something like @cihadturhan's jQuery.aim and add spider sense-like prefetching to smoothState.js.
$('#main').smoothState({ prefetchOn: 'aim' });
locationHeaderA field name to lookup among the headers from the HTTP response to alert smoothState.js of any redirected URL.
smoothState.js makes AJAX requests using XMLHttpRequest, which silently follows redirects. This transparence prevents smoothState.js from knowing if a request resulted in a redirection.
For example, when you visit /about and the server redirects you to /about/company, smoothState.js is only ever informed of a successful response from /about. The locationHeader option gives smoothState.js a HTTP response header to consult and replace the browser's history entry with the real URI.
$('#main').smoothState({ locationHeader: 'X-SmoothState-Location' });
cacheLengthThe number of pages to cache. smoothState.js can cache pages in memory, avoiding the user having to request pages more than once. Cached pages will load instantaneously.
// Default
$('#main').smoothState({ cacheLength: 0 });
loadingClassThe class to apply to the body while a page is still loading, unless the page is received before the animations are complete.
// Default
$('#main').smoothState({ loadingClass: 'is-loading' });
scrollScroll to top after onStart and scroll to hash after onReady. This is default behavior, if you want to implement your own scroll behavior, set scroll: false
// Default
$('#main').smoothState({ scroll: true });
alterRequestA function to alter a request's AJAX settings before it is called. This can be used to alter the requested URL, for example.
// Default
$('#main').smoothState({
// Param `request` is an `Object` that is currently set to be used
alterRequest: function(request) {
// Must return and `Object` that will be used to make the request
return request;
}
});
alterChangeStateA function to alter a history entry's state object before it is modified or added to the browser's history. This can be used to attach serializable data to the history entry, for example.
// Default
$('#main').smoothState({
// Param `state` is an `Object` that contains the container ID, by default
alterChangeState: function(state) {
// Must return a serializable `Object` that is associated with the history entry
return state;
}
});
onBeforeThe function to run before a page load is started.
// Default
$('#main').smoothState({
// `$currentTarget` is a `jQuery Object` of the element, anchor or form, that triggered the load
// `$container` is a `jQuery Object` of the the current smoothState container
onBefore: function($currentTarget, $container) {}
});
onStartThe function to run once a page load has been activated. This is an ideal time to animate elements that exit the page and set up for a loading state.
// Default
$('#main').smoothState({
onStart: {
// How long this animation takes
duration: 0,
// A function that dictates the animations that take place
render: function ($container) {}
}
});
onProgressThe function to run only if the page request is still pending and onStart has finished animating. This is a good place to add something like a loading indicator.
// Default
$('#main').smoothState({
onProgress: {
// How long this animation takes
duration: 0,
// A function that dictates the animations that take place
render: function ($container) {}
}
});
onReadyThe function to run when the requested content is ready to be injected into the page. This is when the page's contents should be updated.
// Default
$('#main').smoothState({
onReady: {
duration: 0,
// `$container` is a `jQuery Object` of the the current smoothState container
// `$newContent` is a `jQuery Object` of the HTML that should replace the existing container's HTML.
render: function ($container, $newContent) {
// Update the HTML on the page
$container.html($newContent);
}
}
});
onAfterThe function to run when the new content has been injected into the page and all animations are complete. This is when to re-initialize any plugins needed by the page.
// Default
$('#main').smoothState({
onAfter: function($container, $newContent) {}
});
smoothState provides some methods and properties, made accessible through the element's data property.
// Access smoothState
var smoothState = $('#main').smoothState().data('smoothState');
// Run method
smoothState.load('/newPage.html');
hrefThe URL of the content that is currently displayed.
cacheAn object containing the cached pages after they are requested.
load(url)This loads the contents of a URL into our container.
fetch(url)This fetches the contents of a URL and caches it.
clear(url)This clears a given page from the cache. If no URL is provided it will clear the entire cache.
restartCSSAnimations()This restarts any CSS animations applying to elements within the smoothState container.
Help! My
$(document).ready()plugins work fine when I refresh but break on the second page load.
smoothState.js provides the onAfter callback function that allows you to re-run your plugins. This can be tricky if you're unfamiliar with how AJAX works.
When you run a plugin on $(document).ready(), it's going to register only on elements that are currently on the page. Since we're injecting new elements every load, we need to run the plugins again, scoping it to just the new stuff.
A good way to do this is to wrap your plugin initializations in a function that we call on both $.fn.ready() and onAfter. You'll want to specify the context each time you initialize the plugins so that you don't double-bind them. This is called a "module execution controller".
We're always looking for:
Overall
Maintained
Code review
npm
Latest release
Releases this year
1,437 followers · starred Aug 2014
3,465 followers · starred Aug 2016
148 followers · starred Jan 2019
118 followers · starred Aug 2014
smoothState.js is a jQuery plugin that progressively enhances page loads to give us control over page transitions. If the user's browser doesn't have the required features, smoothState.js fades into the background and never runs.

Below are some cool sites built with smoothState.js. Feel free to submit a pull request with your own site, or tweet me with a link.
If you need a little help implementing smoothState there are a couple things you could do to get some support:
Please avoid creating a Github issue with personal support requests, to keep the tracker clear for bugs and pull requests.
Imagine, for a second, how disorienting it would be if touching a doorknob teleported you to the other side of the door. Navigating the web feels like using a teleporting doorknob. Layouts change, elements rearrange or disappear, and it takes time for the user to adjust. Smooth transitions reduce the effort it takes for users to get settled into a new environment.
Javascript SPA frameworks, sometimes referred to as MVC frameworks, are a common way to solve this issue. These frameworks often lose the benefits of unobtrusive code. Writing unobtrusive javascript gives us more resilience to errors, and improved performance and accessibility.
smoothState.js provides hooks that can be used to choreograph how elements enter and exit the page during navigation. It uses the time the animations are running to fetch content via AJAX to inject into the page.
smoothState.js doesn't dictate how things on the page should be animated. It supports CSS animations, as well as JS animation libraries like velocity.js.
The project's main goal is to allow developers to add page transitions without having to add any logic to the backend. We keep things unobtrusive at all times.
smoothState.js initializes on containers, not links. Think of a container as a small window object embedded in the page.
id set - a unique hook to tell us what to update on the pageThese requirements makes the website resilient, since it smoothState.js can abort and simply redirect the user if an error occurs. Making each link return a full page also ensures that pages are created with progressive enhancement in mind.
All we need to do to get started is:
#main and include some links inside of it$('#main').smoothState()$(function() {
$('#main').smoothState();
});
By default, smoothState.js will:
smoothState.js will not add page transitions to pages. You'll need to define the animations you want to run using the hooks smoothState.js provides.
onBefore - Runs before a page load has been startedonStart - Runs once a page load has been activatedonProgress - Runs if the page request is still pending and the onStart animations have finishedonReady - Run once the requested content is ready to be injected into the page and the previous animations have finishedonAfter - Runs after the new content has been injected into the page and all animations are completesmoothState.js provides some options that allow customization of the plugin's functionality. The default options are overridden by passing an object into the smoothState function.
$(function(){
'use strict';
var options = {
prefetch: true,
cacheLength: 2,
onStart: {
duration: 250, // Duration of our animation
render: function ($container) {
// Add your CSS animation reversing class
$container.addClass('is-exiting');
// Restart your animation
smoothState.restartCSSAnimations();
}
},
onReady: {
duration: 0,
render: function ($container, $newContent) {
// Remove your CSS animation reversing class
$container.removeClass('is-exiting');
// Inject the new content
$container.html($newContent);
}
}
},
smoothState = $('#main').smoothState(options).data('smoothState');
});
debugIf set to true, smoothState.js will log useful debug information to the console, instead of aborting. For example, instead of redirecting the user to a page on an error, it might log:
No element with an id of “#main” in response from “/about.html”.
// Default
$('#main').smoothState({ debug: false });
anchorsA jQuery selector specifying which anchors within the smoothState element should be bound.
// Default
$('#main').smoothState({ anchors: 'a' });
hrefRegexA regular expression to specify which anchor with a specific href property based on the regex smoothState should bind to. If empty, every href will be permitted.
// Default
$('#main').smoothState({ hrefRegex: '' });
formsA jQuery selector specifying which forms within the smoothState element should be bound.
// Default
$('#main').smoothState({ forms: 'form' });
allowFormCachingControls whether or not form submission responses are preserved in the cache. If set to true, smoothState will store form responses in the cache. This should be set to false unless you understand how caching form results will affect your website's behaviour very well.
// Default
$('#main').smoothState({ allowFormCaching: false });
repeatDelayThe minimum number of milliseconds between click/submit events. User events ignored beyond this rate are ignored. This can be used to ignore double-clicks so that the user's browser history won't become cluttered by incompleted page loads.
// Default
$('#main').smoothState({ repeatDelay: 500 });
blacklistA jQuery selector specifying which elements within the smoothState element should be ignored. This includes both form and anchor elements.
// Default
$('#main').smoothState({ blacklist: '.no-smoothState' });
prefetchThere is a 200ms to 300ms delay between the time that a user hovers over a link and the time they click it. On touch screens, the delay between the touchstart and touchend is even greater. If the prefetch option is set to true, smoothState.js will begin to preload the contents of the URL during that delay. This technique will increase the perceived performance of the site.
// Default
$('#main').smoothState({ prefetch: false });
prefetchOnThe name of the events to listen to from anchors when prefetching.
// Default
$('#main').smoothState({ prefetchOn: 'mouseover touchstart' });
If you would like to throttle the prefetch, do so by firing custom events.
Libraries like @tristen's hoverintent can be used to throttle prefetching based on the user's intent, by triggering a custom intent event. To use it with smoothState.js, set intent as the prefetchOn option.
$('#main').smoothState({ prefetchOn: 'intent' });
Or, for the opposite effect, use something like @cihadturhan's jQuery.aim and add spider sense-like prefetching to smoothState.js.
$('#main').smoothState({ prefetchOn: 'aim' });
locationHeaderA field name to lookup among the headers from the HTTP response to alert smoothState.js of any redirected URL.
smoothState.js makes AJAX requests using XMLHttpRequest, which silently follows redirects. This transparence prevents smoothState.js from knowing if a request resulted in a redirection.
For example, when you visit /about and the server redirects you to /about/company, smoothState.js is only ever informed of a successful response from /about. The locationHeader option gives smoothState.js a HTTP response header to consult and replace the browser's history entry with the real URI.
$('#main').smoothState({ locationHeader: 'X-SmoothState-Location' });
cacheLengthThe number of pages to cache. smoothState.js can cache pages in memory, avoiding the user having to request pages more than once. Cached pages will load instantaneously.
// Default
$('#main').smoothState({ cacheLength: 0 });
loadingClassThe class to apply to the body while a page is still loading, unless the page is received before the animations are complete.
// Default
$('#main').smoothState({ loadingClass: 'is-loading' });
scrollScroll to top after onStart and scroll to hash after onReady. This is default behavior, if you want to implement your own scroll behavior, set scroll: false
// Default
$('#main').smoothState({ scroll: true });
alterRequestA function to alter a request's AJAX settings before it is called. This can be used to alter the requested URL, for example.
// Default
$('#main').smoothState({
// Param `request` is an `Object` that is currently set to be used
alterRequest: function(request) {
// Must return and `Object` that will be used to make the request
return request;
}
});
alterChangeStateA function to alter a history entry's state object before it is modified or added to the browser's history. This can be used to attach serializable data to the history entry, for example.
// Default
$('#main').smoothState({
// Param `state` is an `Object` that contains the container ID, by default
alterChangeState: function(state) {
// Must return a serializable `Object` that is associated with the history entry
return state;
}
});
onBeforeThe function to run before a page load is started.
// Default
$('#main').smoothState({
// `$currentTarget` is a `jQuery Object` of the element, anchor or form, that triggered the load
// `$container` is a `jQuery Object` of the the current smoothState container
onBefore: function($currentTarget, $container) {}
});
onStartThe function to run once a page load has been activated. This is an ideal time to animate elements that exit the page and set up for a loading state.
// Default
$('#main').smoothState({
onStart: {
// How long this animation takes
duration: 0,
// A function that dictates the animations that take place
render: function ($container) {}
}
});
onProgressThe function to run only if the page request is still pending and onStart has finished animating. This is a good place to add something like a loading indicator.
// Default
$('#main').smoothState({
onProgress: {
// How long this animation takes
duration: 0,
// A function that dictates the animations that take place
render: function ($container) {}
}
});
onReadyThe function to run when the requested content is ready to be injected into the page. This is when the page's contents should be updated.
// Default
$('#main').smoothState({
onReady: {
duration: 0,
// `$container` is a `jQuery Object` of the the current smoothState container
// `$newContent` is a `jQuery Object` of the HTML that should replace the existing container's HTML.
render: function ($container, $newContent) {
// Update the HTML on the page
$container.html($newContent);
}
}
});
onAfterThe function to run when the new content has been injected into the page and all animations are complete. This is when to re-initialize any plugins needed by the page.
// Default
$('#main').smoothState({
onAfter: function($container, $newContent) {}
});
smoothState provides some methods and properties, made accessible through the element's data property.
// Access smoothState
var smoothState = $('#main').smoothState().data('smoothState');
// Run method
smoothState.load('/newPage.html');
hrefThe URL of the content that is currently displayed.
cacheAn object containing the cached pages after they are requested.
load(url)This loads the contents of a URL into our container.
fetch(url)This fetches the contents of a URL and caches it.
clear(url)This clears a given page from the cache. If no URL is provided it will clear the entire cache.
restartCSSAnimations()This restarts any CSS animations applying to elements within the smoothState container.
Help! My
$(document).ready()plugins work fine when I refresh but break on the second page load.
smoothState.js provides the onAfter callback function that allows you to re-run your plugins. This can be tricky if you're unfamiliar with how AJAX works.
When you run a plugin on $(document).ready(), it's going to register only on elements that are currently on the page. Since we're injecting new elements every load, we need to run the plugins again, scoping it to just the new stuff.
A good way to do this is to wrap your plugin initializations in a function that we call on both $.fn.ready() and onAfter. You'll want to specify the context each time you initialize the plugins so that you don't double-bind them. This is called a "module execution controller".
We're always looking for:
Overall
Maintained
Code review
npm
Latest release
Releases this year
1,437 followers · starred Aug 2014
3,465 followers · starred Aug 2016
148 followers · starred Jan 2019
118 followers · starred Aug 2014