I'm currently looking for a new job, preferably in the Asia-Pacific region but I would consider other regions as well. If you are hiring or have any leads, I would appreciate if you would drop me a message via the contact form, e-mail (daniel(at)spoodoo.com), Twitter, or LinkedIn.


Sticky Headers in SharePoint 2013

Update 4th of March, 2016: This script has its own Product Page now and all future updates will be posted there. Should you have any questions, problems or bug reports please use the comment section on the Product Page or the Forum.

A popular request was to have sticky headers for lists in SharePoint 2013. This is very useful if you have long lists with loads of columns. Sometimes the user cant remember what a value in one of those uncountable column stands for and has to scroll all the way up (if there’s no pagination). To help those users I wrote a small script that glues the header right underneath the gray bars on top in case the lists header scrolls out of view.

The sticky headers keep all their functionality (like ‘sort’ and stuff like that). They also scroll vertically with the window and adjust their size when the column width suddenly changes (can happen on views with grouping) or when the windows is resized. And last but not least they have some eye candy in terms of a fade-in and fade-out animations.


Enough text, let’s see some pictures!

Sticky header for a single list

Sticky header for a single list

Sticky headers for multiple lists at the same time

Sticky headers for multiple lists at the same time

The sticky header keeps its full functionality

The sticky header keeps its full functionality

Sticky Headers animated GIF

Sticky Headers in action (animated GIF)

The Code

And here’s the code, there’s definitely some room for improvements but for now it’s working quite good:

Please note: I have removed the code from this post in order to ensure that you always get the latest version. Please hit the link at the end of this post to go to the download section and download the script from there. Thanks!

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type="text/javascript">

function sticky_headers () {

	var top_old        = [], top_new        = [],
		bottom_old     = [], bottom_new     = [],
		offsetLeft_old = [], offsetLeft_new = [],
		sticky         = [], header         = [];

	var style = "position:fixed;" +
				"top:65px;" +
				"z-index:1;" +
				"background-color:white;" +
				"box-shadow:3px 3px 5px #DDDDDD;" +
	function updateStickyHeader (event, DOMchange) {
		$('.sticky-anchor', '#DeltaPlaceHolderMain').each(function (i) {

			if(DOMchange) {
				return false;

			function offset() {
					left: offsetLeft_new[i]

			function width() {
				sticky[i].width(header[i].width()).find('th').each(function (j) {
					$(this).width(header[i].find('th:nth-child(' + (j+1) + ')').width())

			top_old[i]        = top_new[i]
			top_new[i]        = Math.round($(this).offset().top - 45)
			bottom_old[i]     = bottom_new[i]
			bottom_new[i]     = Math.round(top_new[i] - 30 + $(this).parents('table').height())
			offsetLeft_old[i] = offsetLeft_new[i]
			offsetLeft_new[i] = Math.round(header[i].offset().left)

			if(offsetLeft_old[i] == offsetLeft_new[i]){
				if(top_old[i] >= 0 && top_new[i] <= 0 || bottom_old[i] <= 0 && bottom_new[i] >= 0) {
				} else if (top_old[i] <= 0 && top_new[i] >= 0 || bottom_old[i] >= 0 && bottom_new[i] <= 0) {
			} else {

	if($('.ms-viewheadertr', '#DeltaPlaceHolderMain').length) {
		$('#s4-workspace').bind('scroll', updateStickyHeader);
		$('.ms-viewheadertr:visible','#DeltaPlaceHolderMain').each(function () {
			if($(this).closest("table").find("tbody > tr").length > 1) {
				header.push($(this).before('<div class="sticky-anchor"><span></span></div>'))
				sticky.push($(this).clone(1).addClass("sticky").insertAfter($(this)).attr('style', style))
				var tbody = $(this).parent("thead").siblings("tbody")
				if(tbody.length > 1) {
					tbody.bind("DOMAttrModified", function(){
							$('#s4-workspace').trigger("scroll", true)
						}, 250)

Put this code into your masterpage and all lists in your SharePoint will have these nice and sticky headers or embed the code only on a specific page if you don’t want to have this feature site-wide. Pleaes note that this script requires jQuery.

Many thanks to Yu-Jie Lin and the blog at http://blog.yjl.im/ for the good starting point!

I would be glad to hear some comments from you if you like the solution (and even more if you don’t like it and have some tips on how to improve it).

Click here to download the script

Tweet about this on TwitterShare on RedditShare on FacebookShare on Google+Share on LinkedInShare on StumbleUponShare on TumblrPin on PinterestDigg thisPrint this pageEmail this to someone

One comment

Comments are closed.