JS and CSS driven sticky table header. Good alternative to position: sticky
when
horizontal scroll and stickiness is needed as well.
- Support vertical and horizontal scroll stickiness at the same time.
- Support for multiple nested scrollable containers.
- Support for actions inside the header.
- Support different top displacement per viewport width.
- No flickering. Element coordinates are not updated on scroll events.
- Smaller than 4kb compressed.
- No dependencies. Can be used in any framework.
npm i --save vh-sticky-table-header
Example usage with React:
import { StickyTableHeader } from 'vh-sticky-table-header';
import React, { FC, useLayoutEffect, useRef } from 'react';
const TableWithStickyHeader: FC = ({ children }) => {
const tableRef = useRef<HTMLTableElement>(null);
const tableCloneRef = useRef<HTMLTableElement>(null);
useLayoutEffect(() => {
if (tableRef.current && tableCloneRef.current) {
// Initialize the sticky header.
const sticky = new StickyTableHeader(
tableRef.current,
tableCloneRef.current,
{ max: 60 }
);
// Make sure to destory the sticky header once the main table is unmounted.
return () => sticky.destroy();
}
}, []);
return (
<>
<div className="table_container">
<table ref={tableRef}>{children}</table>
</div>
<div className="table_container">
<table ref={tableCloneRef} />
</div>
</>
);
};
Example usage with Vue 3:
<script setup>
import { StickyTableHeader } from 'vh-sticky-table-header';
import { onMounted, ref, watchEffect } from 'vue';
const tableRef = ref(null);
const tableCloneRef = ref(null);
onMounted(() => {
watchEffect((onCleanup) => {
if (!tableRef.value && !tableCloneRef.value) return;
const stickyTable = new StickyTableHeader(
tableRef.value,
tableCloneRef.value,
{ max: 0 },
);
onCleanup(() => stickyTable.destroy();
});
});
</script>
<template>
<div class="grid w-full overflow-x-auto overflow-y-hidden md:rounded-lg">
<table ref="tableRef">
<slot />
</table>
</div>
<div class="grid w-full overflow-x-auto overflow-y-hidden shadow-md md:rounded-lg">
<table ref="tableCloneRef" />
</div>
</template>
Requirements (these can be seen in the demo as well):
- The table container
div
elements should have the following css for vertical scrolling to work:.table_container { width: 100%; overflow-x: auto; overflow-y: hidden; }
- The JS logic to determine when to show the sticky header uses
window.document
. The body needs to at be at y = 0 position when the scroll is at y = 0. Make sure that the body is not displaced using child elements withmargin
(ex: in case of sticky site header). Usepadding
instead.
Options are provided to the constructor of the sticky table header instance.
export default class StickyTableHeader {
constructor(tableContainer: HTMLDivElement, cloneContainer: HTMLTableElement, top: {
max: number | string;
[key: number]: number | string;
});
}
Reference to the main table dom element where content is rendered. Must be a table with a table header.
Reference to an empty table dom element. This is where a replica of the table header will be rendered.
Object describing the displacement from top of the viewport for the vertical scrolling.
max
is the default number of pixels or rem
from top.
Any other key, defined in number, will represent a different number of pixels or rem
from top to which to stick,
when the viewport width is less than the key.
- Fix header bottom docking in case of multiple
tbody
tags. merge-request by geic99
- Reduce package size.
- Support header click replication method when table in multiple scroll containers. issue
- Reworked header click replication method. Now when clicking table is not scrolled up. issue
- Added support for multiple table header rows. merge-request by ZEA-repository
- Added support for multiple scrollable containers. issue
- Small performance improvements.
- Fix table header sticking at the bottom of last row of an inner table.
- Fix issue with click mirroring not working due to incorrect coordinates.
- Click mirroring now scrolls higher up (+60px) then only the original table header.
- Improve docking when scrolling past container. Now
offsetTop
is added to the absolute position of the clone table container. - Fix issue where horizontal scrolling would not update on the clone containers horizontal scroll when the scrolling was done in docking state. issue
- Remove leftover
console.log
.
- Hide the clone container (display:none) when not sticky. issue
- Fix issue where quick render and destroy would render the sticky header twice.
- Prevent sticky header overflowing table vertically when scrolling past table.
- Fix ESM module, for webpack compatibility.
- Typing fix.
- Add support for
rem
displacement.