javascriptcssmaterial-uiimagelistscroll-position

Material UI fade scroll styling on ImageList


I have a horizontally scrolling ImageList using Material UI V5, and I would like to fade the edges so that the cutoff isn't as harsh. I have figured out how to fade the edges, but I would only like the edges to fade until the user has scrolled to the start or end of the list (so when the user is at the start of the list the right is faded, and at the end the left is faded, and on larger screens with no scroll there is no fade). What is the easiest way for me to achieve this within MUI ImageList? I can style the object conditionally but can't seem to get scroll position.

enter image description here

import * as React from 'react';
import Image from 'next/image';
import ImageList from '@mui/material/ImageList';
import ImageListItem from '@mui/material/ImageListItem';
import ImageListItemBar from '@mui/material/ImageListItemBar';
import { styled } from "@mui/system"
import { NoEncryption } from '@mui/icons-material';


export default function TitlebarBelowImageList() {

  return (
    <AdBarContainer>
    <ImageList sx={{ 
      width: "100%",
      gridAutoFlow: "column",
      gridTemplateColumns: "repeat(auto-fill,minmax(15em, 1fr)) !important",
      gridAutoColumns: "minmax(15em, 1fr)",
      overflowX:'scroll',
      maskImage: 'linear-gradient(to left, black calc(100% - 48px), transparent 100%)',
      maskImage: 'linear-gradient(to right, transparent 0%, black 48px, black calc(100% - 48px), transparent 100%)',
      }}
      gap= {10}
      variant= 'standard'
      rowHeight= "auto"
      >
      {itemData.map((item) => (
        <ImageListItem key={item.key}>
          <img
            src={`${item.img}?w=248&fit=crop&auto=format`}
            srcSet={`${item.img}?w=248&fit=crop&auto=format&dpr=2 2x`}
            alt={item.title}
            loading="lazy"
            style={{borderRadius: 10}}
          />
          <ImageListItemBar
            title={item.title}
            subtitle={<span>{item.subtitle}</span>}
            position="below"
          />
        </ImageListItem>
      ))}
    </ImageList>
    </AdBarContainer>
  );
}

const itemData = [
  {
    key: 1,
    img: '/img.jpg',
    title: 'title',
    subtitle: 'subtitle',
  },
  {
    key: 2,
    img: '/img.jpg',
    title: 'title',
    subtitle: 'subtitle',
  },
  {
    key: 3,
    img: '/img.jpg',
    title: 'title',
    subtitle: 'subtitle',
  },
  {
    key: 4,
    img: '/img.jpg',
    title: 'title',
    subtitle: 'subtitle',
  },
  {
    key: 5,
    img: '/img.jpg',
    title: 'title',
    subtitle: 'subtitle',
  },
];

Solution

  • Have a look at this working codesandbox which I think is what you are looking for.

    Here is you code updated with the answer:

    import React, { useEffect, useState } from "react";
    import Image from "next/image";
    import ImageList from "@mui/material/ImageList";
    import ImageListItem from "@mui/material/ImageListItem";
    import ImageListItemBar from "@mui/material/ImageListItemBar";
    import { styled } from "@mui/system";
    import { NoEncryption } from "@mui/icons-material";
    
    const itemData = [
      {
        key: 1,
        img: "/img.jpg",
        title: "title",
        subtitle: "subtitle"
      },
      {
        key: 2,
        img: "/img.jpg",
        title: "title",
        subtitle: "subtitle"
      },
      {
        key: 3,
        img: "/img.jpg",
        title: "title",
        subtitle: "subtitle"
      },
      {
        key: 4,
        img: "/img.jpg",
        title: "title",
        subtitle: "subtitle"
      },
      {
        key: 5,
        img: "/img.jpg",
        title: "title",
        subtitle: "subtitle"
      }
    ];
    
    export default function TitlebarBelowImageList() {
      const [horizontalScroll, setHorizontalScroll] = useState(0);
    
      useEffect(() => {
        const imageListEl = document.querySelector("#imageList");
    
        imageListEl?.addEventListener(
          "scroll",
          () => {
            console.log("position left is", imageListEl.scrollLeft);
            setHorizontalScroll(imageListEl?.scrollLeft);
          },
          { passive: true }
        );
      }, [horizontalScroll]);
    
      return (
        <AdBarContainer>
        <ImageList
          id="imageList"
          sx={{
            width: "100%",
            gridAutoFlow: "column",
            gridTemplateColumns: "repeat(auto-fill,minmax(15em, 1fr)) !important",
            gridAutoColumns: "minmax(15em, 1fr)",
            overflowX: "scroll",
            maskImage:
              horizontalScroll > 0
                ? [
                    "linear-gradient(to left, black calc(100% - 48px), transparent 100%)",
                    "linear-gradient(to right, transparent 0%, black 48px, black calc(100% - 48px), transparent 100%)"
                  ]
                : [""]
          }}
          gap={10}
          variant="standard"
          rowHeight="auto"
        >
          {console.log("pos", horizontalScroll)}
          {itemData.map((item) => (
            <ImageListItem key={item.key}>
              <img
                src={`${item.img}?w=248&fit=crop&auto=format`}
                srcSet={`${item.img}?w=248&fit=crop&auto=format&dpr=2 2x`}
                alt={item.title}
                loading="lazy"
                style={{ borderRadius: 10 }}
              />
              <ImageListItemBar
                title={item.title}
                subtitle={<span>{item.subtitle}</span>}
                position="below"
              />
            </ImageListItem>
          ))}
        </ImageList>
        </AdBarContainer>
      );
    }
    

    Hope it helps.