Tips for preventing a table from showing up while scrolling unnecessarily when utilizing a heading with the CSS position property set to 'sticky'

Currently, I am facing an issue with creating a sticky header for my table. The problem arises when the header of the table has rounded edges (top right and top left) along with a box-shadow applied to the entire table. As the user scrolls through the table, the box-shadow also moves, causing a visible gap between the header and the beginning of the table.

To provide better context, please refer to this video demonstration showcasing the mentioned issues.

The structure of my simple header is defined in 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>
    );
}

In DataTablesStyles.js, the styling for the table and headers is specified:

// 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',
}

If you grasp the gist of my query, how can I prevent the scrolling behavior of the shadow and eliminate the visible gap?

Answer №1

To achieve the desired result, I have implemented some changes. Firstly, it is important to note that the scrollbar should be exclusively on the table body and not affect the header section. Placing the scrollbar solely on the content area ensures a clean separation between the scrollable content and the fixed header.

https://i.stack.imgur.com/LGVkr.gif

Several additional class names were introduced to accommodate this adjustment. Working with tables can be quite intricate due to its historical roots in HTML, often requiring clever CSS tricks to properly layout rows and headers using techniques like display: table. For instance, setting the display of the tbody to block while maintaining the overall table structure intact demanded careful tweaking.

Now, you have control over the height through the .TableBodyStyle class, currently set at 400px for demonstration purposes.

Additionally, here is a codesandbox link for your reference: 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;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to align a button vertically centered next to a matInput using Angular Material

Is there a way to vertically center a button next to matInput in Angular material? The submit button appears too low compared to the "First Name" input field, as shown in the images below: Your response can be provided by forking my stackblitz project her ...

"The React Navigation header is not behaving as expected in hiding or showing itself

I'm currently utilizing react navigation and I have a requirement to toggle the header visibility based on button onPress events. However, despite being able to hide the header successfully, I am facing challenges in showing it again using another fun ...

Survey with results routing based on rating

I am looking to incorporate a basic survey on my website featuring a few multiple choice questions. Each question will be assigned a score, and upon completing the survey, users will be redirected to a personalized page based on their overall score. Doe ...

Why does the behavior of creating relative URLs with `new URL()` change when the first parameter is a variable?

Recently, I've been diving into the world of web workers in NextJs. I tried to follow their example, but ran into an issue that's been bugging me. It seems that passing the worker relative URL as a variable to new URL(url, baseUrl) isn't wor ...

Navigating through the Express.js routes incorrectly

I currently have 3 different express.js routes set up: app.get('/packages/:name', (req, res) => {...}); app.get('/packages/search/', (req, res) => {...}); app.get('/packages/search/:name', (req, res) => {...}); At t ...

JavaScript's addition of CSS animation not functioning as intended

I am facing an issue with a web page utilizing Bootstrap 5. The webpage consists of one element stacked on top of another. My goal is to fade-out the top element after a certain period. Here is what I have tried: HTML <div id="host" class=&qu ...

A guide on coding the source tag script for a payment form in CodeIgniter, specifically for a JavaScript form

Scenario: I have a variable called $data['tabdata'] that I am passing from controller C to view V. This variable includes a script element pointing to http://example.com/1.js. Problem: The script in 1.js is not running properly in the view. This ...

Update the image with a new one using jQuery and PHP, then refresh the page to see

I'm currently utilizing simpleImage, a PHP image manipulation library. My aim is to externally rotate an image using AJAX and replaceWith functions. It successfully replaces the image, but unfortunately it doesn't refresh after rotation. Here&ap ...

How can I utilize Hooks to effectively filter arrays?

Currently, I am working on transitioning from a class-based function to a stateless function. As part of this process, I am refactoring my code by updating each event handler that uses this.SetState to use useState instead (in this case setMovies). Below ...

Using PHP to send variables to an AJAX function via parameters

I've encountered an issue while attempting to pass 4 variables through the parameters of the ajax function. The variables I'm trying to pass include the URL, action, ID, and timeout in milliseconds. Unfortunately, the function is not accepting th ...

Titanium: Picture -> "automatically"

Imagine there is an image named hello.png with the dimensions of 200x100. A button is then created using this hello.png as shown below: var btn = Titanium.UI.createButton({ bottom : 50, backgroundImage : "images/hello.png", width:100, height:"auto"; }); w ...

What is the best way to selectively adjust object parameters in unit testing?

In my module, I have an object with several parameters. I want to rewire only specific parameters of this object. Here is a snippet from my 'module.js' file: var obj = { param_A: 'valueA', param_B: 'valueB', param_C: &a ...

Is jQuery the key to Masonry's stacking magic?

Hey there, I could really use some assistance with my website at this link: I thought jQuery Masonry would stack the objects closely together, but when I randomize the div boxes, there are large gaps between them. Can anyone explain why this is happening? ...

CSS gallery slideshow with images that smoothly fade-in and fade-out at a specified location

In the image below, at position 4 (marked by yellow circle) from the left where picture 6 is displayed, I want a cross-fade (fade-in/fade-out) gallery of images to take place. Specifically at position 4, I am looking for a cross-fade (fade-in/fade-out) ef ...

Issues arise when using ng-repeat in conjunction with ng-click

I am facing some new challenges in my spa project with angularjs. This is the HTML snippet causing issues: <a ng-repeat="friend in chat.friendlist" ng-click="loadChat('{{friend.friend_username}}')" data-toggle="modal" data-target="#chat" d ...

The bar graph dataset is not correctly configured when utilizing ng2 charts and ng5-slider within an Angular framework

Currently, I am working with a range slider and bar graph. My goal is to dynamically change the color of the bar graph using the range slider. While I have managed to successfully alter the color of the bars, I am facing an issue where the data displayed ...

What strategies can I use to control the DOM within the onScroll event in ReactJS?

I am currently working on implementing an arrow-up button that should be hidden when I am at the top of my page and displayed once I scroll further down. However, I am facing issues with manipulating the DOM inside my handleScroll function to achieve this. ...

Utilizing Node.js and Jasmine: Preventing the invocation of a Promise function to avoid executing the actual code results in DEFAULT_TIMEOUT_INTERVAL

There is a function below that returns a promise. public async getAverageHeadCount(queryParams: Params, childNode: any, careerTrackId: string): Promise<Metric> { const queryId = this.hierarchyServiceApiUrl + "rolling-forecast/ahc/" + q ...

The property 'dateClick' is not found in the 'CalendarOptions' type in version 6 of fullcalendar

Below is the Angular code snippet I am currently using: calendarOptions: CalendarOptions = { plugins: [ dayGridPlugin, timeGridPlugin, listPlugin ], initialView: 'dayGridMonth', headerToolbar: { left: 'prev today next' ...

Include the data-title attribute within the <td> elements of my datatables

To apply the magic of jQuery datatables to all my tables, I use datatables. For responsive tables, I add data-title to my td's. Is there a way to automatically add data-title to all my td's like below? <td data-title="Fruit">Apple</td&g ...