How to avoid table appearing during scrolling (where it is not required) when using heading with position: 'sticky'

Viewed 67

My question is related to having a header in my table that has the style - position: 'sticky'. And that's where all the problems come from. Now more

I set a sticky header to make it easy for the user to scroll through long tables. But the header in the table has rounded edges (top right and top left), and the table itself has a box-shadow. And it turns out that when the user scrolls the table, the box-shadow scrolls along with the table, and space is visible in the gap between the header and the beginning of the table.

Perhaps the description is confusing, here is a video (note the box-shadow and rounded edges of the table)

My header very simple

Header.jsx

 import { styles } from "../DataTablesStyles";

 export default function Header() {
    return (
        <TableHead sx={{position: 'sticky',top: '0px',zIndex: '1'}}>
            <TableRow >
                <TableCell style={styles.TableHeaderStyleFirst}>Actions</TableCell>
                <TableCell style={styles.TableHeaderStyle}>Status</TableCell>
                <TableCell style={styles.TableHeaderStyle}>Device ID</TableCell>
                <TableCell style={styles.TableHeaderStyle}>Model</TableCell>
                <TableCell style={styles.TableHeaderStyle}>Operation<br></br>System</TableCell>
                <TableCell style={styles.TableHeaderStyle}>Api<br></br>level</TableCell>
                <TableCell style={styles.TableHeaderStyle}>Last activity</TableCell>
                <TableCell style={styles.TableHeaderStyleLast}></TableCell>
            </TableRow>
        </TableHead>
    );
}

DataTablesStyles.js

// In TableStyle I define the style of the whole table
const TableStyle = {
    borderTopRightRadius: '8px',
    borderTopLeftRadius: '8px',
    alignItems: 'center',
    justifyContent: "flex-end",
    padding: '16px',
    minWidth: '750px',
    boxShadow: '0px 0px 10px 0.1px rgba(124, 159, 236, 0.3)',
}

const TableHeaderStyle = {
    fontWeight: '400',
    fontSize: '14px',
    letterSpacing: '0.4px',
    color: 'black',
    backgroundColor: '#EAECF4',
    textAlign: 'center',
    padding: '2px',
}

const TableHeaderStyleFirst = {
    borderTopLeftRadius: '8px',
    fontWeight: '400',
    fontSize: '14px',
    letterSpacing: '0.4px',
    color: 'black',
    backgroundColor: '#EAECF4',
    textAlign: 'center',
    padding: '2px',

}

const TableHeaderStyleLast = {
    borderTopRightRadius: '8px',
    fontWeight: '400',
    fontSize: '14px',
    letterSpacing: '0.4px',
    color: 'black',
    backgroundColor: '#EAECF4',
    borderTopRightRadius: '8px',
    textAlign: 'center',
    padding: '2px',
}

I think you already understand the essence of my question. How to make it so that the shadow does not scroll and the gap is not visible

1 Answers

I've made a few changes to get this right. Firstly, I think you really want the scrollbar to be on the table body, and not the bit with the header as well. This makes more sense because only the content then has a scrollbar. It also has the affect the header is no longer overlaid (but it still sticks to the top) since the header is no longer part of the scroll content.

overlaid header

I had to add a few more class names here and there to support this change. It's admittedly very fiddly - tables are on of the more ancient parts of the HTML spec and you have to apply various tricks with tricking the rows/header etc to lay out properly with display: table in a few places -- since to put the scroll on the tbody you have to make that display: block and that would otherwise mess up the table/cell layout.

Anyway, here it is. You will now control the height in the .TableBodyStyle which I've set to 400px for demonstration purposes.

Also here is a codesandbox: https://codesandbox.io/s/awesome-brook-i88vim

DevicesTable:

import { Table, TableBody, TableContainer } from "@mui/material";
import DevicesTableHeader from "./DevicesTableHeader";
import DevicesTableCell from "./DevicesTableCell";

export default function DevicesTable() {
  return (
    <TableContainer className="TableContainerGridStyle">
      <Table className="TableStyle">
        <DevicesTableHeader />
        <TableBody className="TableBodyStyle">
          <DevicesTableCell />
          <DevicesTableCell />
          <DevicesTableCell />
          <DevicesTableCell />
          <DevicesTableCell />
          <DevicesTableCell />
          <DevicesTableCell />
          <DevicesTableCell />
          <DevicesTableCell />
          <DevicesTableCell />
        </TableBody>
      </Table>
    </TableContainer>
  );
}

DevicesTableCell:

import React from "react";
import { TableCell, TableRow } from "@mui/material";
import "./DataTablesStyles.css";

export default function DevicesTableCell() {
  return (
    <TableRow className="TableCellStyle">
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
      <TableCell>Some Text</TableCell>
    </TableRow>
  );
}

DevicesTableHeader:

import "./DataTablesStyles.css";
import { TableCell, TableHead, TableRow } from "@mui/material";

export default function DevicesTableHeader() {
  return (
    <TableHead
      sx={{
        display: "table",
        tableLayout: "fixed",
        width: "100%"
      }}
    >
      <TableRow className="TableRowStyle">
        <TableCell className="TableHeaderStyle">Actions</TableCell>
        <TableCell className="TableHeaderStyle">Status</TableCell>
        <TableCell className="TableHeaderStyle">Device ID</TableCell>
        <TableCell className="TableHeaderStyle">Model</TableCell>
        <TableCell className="TableHeaderStyle">
          Operation<br></br>System
        </TableCell>
        <TableCell className="TableHeaderStyle">
          Api<br></br>level
        </TableCell>
        <TableCell className="TableHeaderStyle">Last activity</TableCell>
        <TableCell className="TableHeaderStyle"></TableCell>
      </TableRow>
    </TableHead>
  );
}

The CSS:

.TableContainerGridStyle {
  overflow: visible !important;
}

.TableStyle {
  display: block;
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
  align-items: center;
  justify-content: flex-end;
  min-width: 750px;
  box-shadow: 0px 0px 10px 0.1px rgba(124, 159, 236, 0.3);
}

.TableHeaderStyle {
  font-weight: 400;
  font-size: 14px;
  letter-spacing: 0.4px;
  color: black;
  background-color: #eaecf4;
  padding: 2px 16px;
}

.TableHeaderStyle:first-child {
  border-top-left-radius: 8px;
  padding: 2px 16px;
}

.TableHeaderStyle:last-child {
  border-top-right-radius: 8px;
  padding: 2px 25px 2px 22px;
}

.TableCellStyle {
  border-top: 2px solid #eaecf4;
  border-bottom: 1.1px solid #eaecf4;
  background-color: #ffffff;
  display: table;
  table-layout: fixed;
  width: 100%;
}

tr.TableCellStyle {
  display: table;
}

.TableCellStyle td:last-child {
  padding-right: 22px;
}

.TableBodyStyle {
  display: block !important;
  overflow: overlay;
  table-layout: fixed;
  max-height: 400px;
}

.TableBodyStyle tr:first-child {
  border-top: 0;
}

.TableBodyStyle tr:last-child {
  border-bottom: 0;
}

Related