JS and CSS driven sticky table header. Good alternative to position: sticky
when
horizontal scroll and stickiness is needed as well.
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):
div
elements should have the following css for vertical scrolling to work:
.table_container {
width: 100%;
overflow-x: auto;
overflow-y: hidden;
}
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 with margin
(ex: in case of sticky site header). Use padding
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;
});
}
tableContainer
Reference to the main table dom element where content is rendered. Must be a table with a table header.
cloneContainer
Reference to an empty table dom element. This is where a replica of the table header will be rendered.
top
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.
tbody
tags. merge-request by geic99offsetTop
is added to the absolute position
of the clone table container.console.log
.rem
displacement.