skip to Main Content

I have a simple calendar view which statically can be coded as the React component below. There is a parent container and it contains two containers timeslot and days. I want them next to each other so i used flex property. Now i want container to be some fixed size and want the overflow items to scroll. When i scroll i want headers to stick. The timeHeader and dayHeader stops sticking after I scroll 40% of the vertical length. I am stuck on this for a while. Pls help!

Rendered Image

Not sticking header

import React from "react";
import "./Test.css";

function Test() {
    return (
        <div className="parent">
            <div className="timeslot">
                <div className="timeHeader">Time</div>
                <div>
                    <ul>
                        <li>7:00 a.m</li>
                        <li>8:00 a.m</li>
                        <li>9:00 a.m</li>
                        <li>10:00 a.m</li>
                        <li>11:00 a.m</li>
                        <li>12:00 p.m</li>
                        <li>1:00 p.m</li>
                        <li>2:00 p.m</li>
                        <li>3:00 p.m</li>
                        <li>4:00 p.m</li>
                        <li>5:00 p.m</li>
                        <li>6:00 p.m</li>
                        <li>7:00 p.m</li>
                        <li>8:00 p.m</li>
                        <li>9:00 p.m</li>
                        <li>10:00 p.m</li>
                    </ul>
                </div>
            </div>
            <div className="days">
                <div className="dayHeader">Days</div>
                <div className="dayslots">
                    <div>
                        <ul>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                            <li>1</li>
                        </ul>
                    </div>
                    <div>
                        <ul>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                            <li>2</li>
                        </ul>
                    </div>
                    <div>
                        <ul>
                            <li>3</li>
                            <li>3</li>
                            <li>3</li>
                            <li>3</li>
                            <li>3</li>
                            <li>3</li>
                            <li>3</li>
                            <li>3</li>
                            <li>3</li>
                            <li>3</li>
                            <li>3</li>
                            <li>3</li>
                            <li>3</li>
                            <li>3</li>
                        </ul>
                    </div>
                    <div>
                        <ul>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                            <li>4</li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    );
}

export default Test;

and its CSS

.parent {
    display: flex;
    width: 400px;
    height: 100px;
    overflow: scroll;
}

.timeHeader {
    position: sticky;
    top: 0;
    background-color: white;
}

.timeslot {
    position: sticky;
    left: 0;
    z-index: 2;
    background: white;
}

.days {
    flex: 5;
}

li {
    min-width: 100px;
}

.dayslots {
    display: flex;
}

.dayHeader {
    background-color: white;
    position: sticky;
    top: 0;
}

The data inside the li tag, you can ignore it, it could be anything. All i want to fix is Time Header to stick all the time. Day header to stick when i scroll vertically and time i.e 7:00am… to stick when i scroll horizontally.

2

Answers


  1. Your issue is with .timeslots css property. Almost what you’re looking for

    .parent {
        display: flex;
        width: 400px;
        height: 200px; /* Adjusted for more height */
        overflow: auto; /* Changed to auto */
    }
    
    .timeHeader, .dayHeader {
        position: sticky;
        top: 0;
        background-color: white;
    }
    
    .days {
        flex: 5;
        overflow-x: auto;
        }
    
    li {
        min-width: 100px;
    }
    
    .dayslots {
        display: flex;
    }
    
    Login or Signup to reply.
  2. Now I want container to be some fixed size.

    For flex items to shrink over their content size to fit to the container size, you need to set the corresponding min-width (or height) to 0, so add min-width:0 on the timeslot and days container.

    I want the overflow items to scroll. When I scroll I want headers to stick.

    This can be solved by flex box flex-direction: column; and as above mentioned min-height: 0 to allow the huge lists to shrink over their content size. The lists container can now shrink, and setting overflow-y: scroll (or auto) on these two huge lists can work.

    The final html and css will look like this:

    .parent {
      border: 1px solid red;
      /*Border added to make the example more clear*/
      display: flex;
      width: 400px;
      height: 100px;
    }
    
    .timeslot {
      /* position: sticky; removed because not needed anymore*/
      left: 0;
      z-index: 2;
      background: white;
      display: flex;
      flex-direction: column;
      min-width: 0;
    }
    
    .timeHeader {
      /* position: sticky; removed because not needed anymore*/
      /* top: 0; removed because not needed anymore*/
      background-color: white;
    }
    
    .timeslots {
      min-height: 0;
      display: flex;
      flex-direction: column;
      overflow-y: scroll
    }
    
    .days {
      min-width: 0;
      min-height: 0;
      flex: 5;
      height: 100%;
      display: flex;
      flex-direction: column;
    }
    
    li {
      min-width: 100px;
    }
    
    .dayslots {
      min-height: 0;
      display: flex;
      overflow-y: scroll
    }
    
    .dayHeader {
      background-color: white;
      /* position: sticky; removed because not needed anymore*/
      /* top: 0; removed because not needed anymore*/
    }
    <div class="parent">
      <div class="timeslot">
        <div class="timeHeader">Time</div>
        <div class="timeslots">
          <ul>
            <li>7:00 a.m</li>
            <li>8:00 a.m</li>
            <li>9:00 a.m</li>
            <li>10:00 a.m</li>
            <li>11:00 a.m</li>
            <li>12:00 p.m</li>
            <li>1:00 p.m</li>
            <li>2:00 p.m</li>
            <li>3:00 p.m</li>
            <li>4:00 p.m</li>
            <li>5:00 p.m</li>
            <li>6:00 p.m</li>
            <li>7:00 p.m</li>
            <li>8:00 p.m</li>
            <li>9:00 p.m</li>
            <li>10:00 p.m</li>
          </ul>
        </div>
      </div>
      <div class="days">
        <div class="dayHeader">Days</div>
        <div class="dayslots">
          <div>
            <ul>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
              <li>1</li>
            </ul>
          </div>
          <div>
            <ul>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
              <li>2</li>
            </ul>
          </div>
          <div>
            <ul>
              <li>3</li>
              <li>3</li>
              <li>3</li>
              <li>3</li>
              <li>3</li>
              <li>3</li>
              <li>3</li>
              <li>3</li>
              <li>3</li>
              <li>3</li>
              <li>3</li>
              <li>3</li>
              <li>3</li>
              <li>3</li>
            </ul>
          </div>
          <div>
            <ul>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
              <li>4</li>
            </ul>
          </div>
        </div>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search