I have a sticky MUI List. I also have another list with just the headers which when clicked on will scroll the sticky list and take me to the corresponding category. However, I am not able to make it work when I scroll through the sticky list and the corresponding list header on the other list should be selected. I am using @makotot/ghostui to achieve scrollspy but its not working. Please advice.
This is my code.
import * as React from "react";
import Grid from "@mui/material/Grid";
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import ListItemText from "@mui/material/ListItemText";
import ListSubheader from "@mui/material/ListSubheader";
import ListItemButton from "@mui/material/ListItemButton";
import Divider from "@mui/material/Divider";
import { map } from "lodash";
import { Scrollspy } from "@makotot/ghostui";
const categories = [0, 1, 2, 3, 4];
export default function PinnedSubheaderList() {
const sectionRefs = React.useMemo(
() => categories.map((i) => React.createRef<HTMLUListElement>()),
[]
);
const [selected, setSelected] = React.useState<number>(0);
const handleChangeCategory = (category: number): void => {
let categoryItem = document.getElementById(category.toString());
categoryItem &&
categoryItem.scrollIntoView({ behavior: "smooth", block: "start" });
setSelected(category);
};
return (
<Grid container spacing={2}>
<Scrollspy sectionRefs={sectionRefs} offset={-100}>
{({ currentElementIndexInViewport }) => (
<>
{console.log(
"currentElementIndexInViewport",
currentElementIndexInViewport
)}
<Grid item md={6} xs={4}>
<List
sx={{ border: `1px solid grey`, my: 2 }}
dense
disablePadding
data-cy="nav-wrapper"
>
{map(categories, (category, index) => (
<React.Fragment key={category}>
<ListItem disablePadding data-cy={`nav-item`}>
<ListItemButton
selected={currentElementIndexInViewport === index}
onClick={() => handleChangeCategory(category)}
>
<ListItemText primary={category} />
</ListItemButton>
</ListItem>
<Divider />
</React.Fragment>
))}
</List>
</Grid>
<Grid item md={6} xs={4}>
<List
sx={{
width: "100%",
bgcolor: "background.paper",
position: "relative",
overflow: "auto",
maxHeight: 300,
"& ul": { padding: 0 }
}}
subheader={<li />}
data-cy="section-wrapper"
>
{categories.map((sectionId, sectionIndex) => (
<li key={`section-${sectionId}`} id={sectionId.toString()}>
<ul ref={sectionRefs[sectionIndex]}>
<ListSubheader>{`I'm sticky ${sectionId}`}</ListSubheader>
{[0, 1, 2].map((item) => (
<ListItem key={`item-${sectionId}-${item}`}>
<ListItemText primary={`Item ${item}`} />
</ListItem>
))}
</ul>
</li>
))}
</List>
</Grid>
</>
)}
</Scrollspy>
</Grid>
);
}
Stackblitz link: Link
You need to pass rootSelector
prop to your Scrollspy
component.
In order to do this, first, you can set a unique id
to your List component like this:
<List
sx={{
width: "100%",
bgcolor: "background.paper",
position: "relative",
overflow: "auto",
maxHeight: 300,
"& ul": { padding: 0 }
}}
subheader={<li />}
data-cy="section-wrapper"
id="my-list-root"
>
And then pass its querySelector string ("#my-list-root"
) to the Scrollspy
like this:
<Scrollspy
sectionRefs={sectionRefs}
offset={-100}
rootSelector="#my-list-root"
>
You can take a look at this sandbox for a live working example of this solution.