mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
93.74k stars 32.24k forks source link

[Autocomplete] Adding items to options causes scroll to go to the top of the list (paging) #30249

Closed LuigiMaestrelli closed 1 year ago

LuigiMaestrelli commented 2 years ago

Duplicates

Latest version

Current behavior šŸ˜Æ

I'm implementing async load with pagination with the Autocomplete. When the listbox is open and the user scroll to the bottom, we load the next page and add the new options. After adding, the position of the scroll on the listbox is reseted and the scroll goes to the top.

Expected behavior šŸ¤”

The scroll position should not change so the user can continue the search for the option

Steps to reproduce šŸ•¹

I've used the Select Country example in the docs and tweek to load the countries with paging. I was abe to reproduce the issue without any async request, just loading more items from the fixed array.

https://codesandbox.io/s/confident-kare-5n6i6

Context šŸ”¦

No response

Your environment šŸŒŽ

@emotion/react: 11.7.1
@emotion/styled: 11.6.0
@mui/material: 5.2.4
react: 17.0.2

`npx @mui/envinfo` System: OS: Windows 10 10.0.19044 Binaries: Node: 16.12.0 - C:\Program Files\nodejs\node.EXE Yarn: 1.22.17 - C:\Program Files\nodejs\yarn.CMD npm: 8.3.0 - C:\Program Files\nodejs\npm.CMD Browsers: Chrome: Not Found Edge: Spartan (44.19041.1266.0), Chromium (96.0.1054.57)
marr commented 2 years ago

I've been trying to get help with this same issue but have received: no response on one ticket, and closure of another ticket with no explanation.

This CSB also illustrates the issue: https://codesandbox.io/s/autocomplete-scroll-bug-39wfv?file=/src/App.js

LuigiMaestrelli commented 2 years ago

Don't now if helps, but I have an older project running some v4 version and this kind of use was working. At the time the Autocomplete component was still in the lab package

andrejunges commented 2 years ago

Indeed this issue didn't exist on v4.

Looks like the problem is this logic https://github.com/mui-org/material-ui/blob/3735493e98b0f15390642f4b134eff0212c652a6/packages/mui-base/src/AutocompleteUnstyled/useAutocomplete.js#L341 when there's no selected item.

ShivamTyagi12345 commented 2 years ago

i would like to help /assign

glaucoheitor commented 2 years ago

Hey @ShivamTyagi12345, are you still working on this issue? I am currently facing the exact same problem and would like to work on it if needed. Thanks!

ShivamTyagi12345 commented 2 years ago

Hey @ShivamTyagi12345, are you still working on this issue? I am currently facing the exact same problem and would like to work on it if needed. Thanks!

yes @glaucoheitor thanks for checking in.yes! I am working on my PR

abhishekdubey1 commented 2 years ago

@ShivamTyagi12345 if you need help, I would also like to help with this. Thanks.

ShivamTyagi12345 commented 2 years ago

@ShivamTyagi12345 if you need help, I would also like to help with this. Thanks.

Sure , if u have done any commits ,I would be happy to look and collaborate

kshitij-p commented 2 years ago

@ShivamTyagi12345 Hey how is your PR going ? I am working on this issue as well right now as well. Would love to help and collaborate. For anyone else also looking into this - https://github.com/mui-org/material-ui/blob/3735493e98b0f15390642f4b134eff0212c652a6/packages/mui-base/src/AutocompleteUnstyled/useAutocomplete.js#L373

The above line seems to be responsible for scrolling the list to the top and temporarily commenting it out seems to stop this happening. I don't know why this is happening however, but I am looking into it rn.

ShivamTyagi12345 commented 2 years ago

/unassign

ajlamarc commented 2 years ago

Need a contribution for school, I will also look into this issue

kshitij-p commented 2 years ago

Opened a PR #30719 proposing a fix. Please read the PR message provided with it which includes a question I have regarding the demos/docs part of the PR.

aakash-lohono commented 2 years ago

Hi, as an intermediate solution

observe role="list-box", useAutocomplete expects it to be role="listbox"

import React, { ForwardedRef, forwardRef, useImperativeHandle, useRef } from "react";

interface ListBoxProps extends React.HTMLAttributes<HTMLUListElement> {
}

const ListBox = forwardRef(
  function ListBoxBase (
    props: ListBoxProps,
    ref: ForwardedRef<HTMLUListElement>,
  ) {
    const { children, ...rest } = props;

    const innerRef = useRef<HTMLUListElement>(null);

    useImperativeHandle<NullableUlElement, NullableUlElement>(ref, () => innerRef.current);

    return (
      <ul
        {...rest}
        ref={innerRef}
        role="list-box"
      >
        {children}
      </ul>
    );
  },
);

export default ListBox;

type NullableUlElement = HTMLUListElement | null;
import React from "react";
import { Autocomplete } from "@mui/material";
import ListBox from "./ListBox";

function HelloWorld () {
  return (
    <Autocomplete 
      {...someProps}
      ListboxComponent={ListBox}
    />
  );
}

this will also do away with hover and selection styles, to fix that, add the following somewhere globally

.MuiAutocomplete-popper .MuiAutocomplete-option[aria-selected='true'] {
  background: dodgerblue; // change accordingly
  color: white; // change accordingly
}

.MuiAutocomplete-popper .MuiAutocomplete-option[role='option'][aria-selected='false']:hover {
  background: rgba(0, 0, 0, 0.1); // change accordingly
}
alveloper commented 2 years ago

Hi, Is there any progress in here?

tugay-radity commented 2 years ago

Hello, we have the same issue, when will this get fixed?

sirartemis commented 2 years ago

Hi , everybody! @LuigiMaestrelli , until the bug is fixed, you can try my solution. I hope it gives a result similar to what you expected

https://codesandbox.io/s/clever-noether-5b93i2?file=/Autocomplete.js

LuigiMaestrelli commented 2 years ago

Hi , everybody! @LuigiMaestrelli , until the bug is fixed, you can try my solution. I hope it gives a result similar to what you expected

https://codesandbox.io/s/clever-noether-5b93i2?file=/Autocomplete.js

It seems to have se same problem, the scroll resets when a new page is loaded. For now, I'm using the solution from @aakash-lohono

devcydo commented 2 years ago

Hi! I would like to contribute, anyone working on this?

ysheep-js commented 2 years ago

Hi , everybody! @LuigiMaestrelli , until the bug is fixed, you can try my solution. I hope it gives a result similar to what you expected https://codesandbox.io/s/clever-noether-5b93i2?file=/Autocomplete.js

It seems to have se same problem, the scroll resets when a new page is loaded. For now, I'm using the solution from @aakash-lohono

You need to copy ./Autocompletes.js to ./src/Autocompletes.js, then it works.

mnajdova commented 2 years ago

I've closed the ongoing PR on this issue, there wasn't any activity for some time. For anyone coming on the issue and want to try a fix, https://github.com/mui/material-ui/pull/30719#issuecomment-1064914713 could be a good start.

skypyxis commented 2 years ago

Hi , everybody! @LuigiMaestrelli , until the bug is fixed, you can try my solution. I hope it gives a result similar to what you expected https://codesandbox.io/s/clever-noether-5b93i2?file=/Autocomplete.js

It seems to have se same problem, the scroll resets when a new page is loaded. For now, I'm using the solution from @aakash-lohono

You need to copy ./Autocompletes.js to ./src/Autocompletes.js, then it works.

This works (storing scroll position and setting it after new data is loaded and appended) but it has one problem: If we scroll the results in the list with the keyboard (down arrow key) when new data is appended the focused item goes back to the first item in the list. Any idea how can we solve this?

MatetlotDev commented 2 years ago

Hi, I had the same issue for creating a paginated Autocomplete Dropdown with Material-ui. Every time the component refresh the list goes back to the top. The problem is that when we add some options to the list two props get updated and re-render the component. So here's what I did for a workaround :

`
import React, { useState, useEffect, useRef } from 'react';

const [position, setPosition] = useState(0);
const listElem = useRef();
const mounted = useRef();

useEffect(() => {
    if (!mounted.current) mounted.current = true;
    else if (position && listElem.current) 
         listElem.current.scrollTop = position - listElem.current.offsetHeight;
  })

// Autocomplete
          ListboxProps={{
          ref: listElem,
          onScroll: ({ currentTarget }) => {
            const scrollPosition =
              currentTarget.scrollTop + currentTarget.clientHeight;

            if (currentTarget.scrollHeight - scrollPosition <= 1 && nextPage) {
              setPosition(scrollPosition);
              loadMore.current.style.display = 'block';
              onInputValueChange(null, nextPage);
            }
          },
        }}

`

Hope it helps !

MostafaKMilly commented 2 years ago

Thanks @aakash-lohono the problem was solved Actually, to solve this problem we just need to pass role: "list-box" as to ListboxProps

Saul-Garcia commented 2 years ago

Thanks @aakash-lohono the problem was solved Actually, to solve this problem we just need to pass role: "list-box" as to ListboxProps

@MostafaKMilly by changing the role to "list-box", can you still access to the list elements with the keyboard?. I tried but breaks accesibility for me.

MostafaKMilly commented 2 years ago

@Saul-Garcia Yes it breaks accessing options elements using keyboard :)

michaldudak commented 1 year ago

There is another open issue describing this problem: #29508. I'm closing this one and let's continue the discussion in the original issue.

devandrews commented 1 year ago

Thanks @aakash-lohono the problem was solved Actually, to solve this problem we just need to pass role: "list-box" as to ListboxProps

For the ones with persisting errors, this solution works when you are not using a custom ListboxComponent. As mine was not necessary it solves the issue.

JakubKontra commented 1 year ago

Hello guys, thanks for your advices. When will it be merged? :)

dbehmoaras commented 1 year ago

If anyone is still having issues with this, try this approach:

To solve this in our codebase, I followed the approach in the youtube link below instead, using the MUI text field for the input and the MUI popper for the dropdown feature, effectively rebuilding the Autocomplete using two separate components. In our case, I used the IntersectionObserver to fire fetchMore query when reaching the bottom element (customizable to your desire of course) and used the ResizeObserver to make it responsive to viewport size. With this approach, it helps to think of infinite scroll as a paginated query, increasing the offset every time you reach the bottom of the list. You could get fancy as well by adding a loader each time the fetchMore query fires. https://www.youtube.com/watch?v=NZKUirTtxcg

Full credit goes to Web Dev Simplified for sharing this approach. (Before anyone asks, no I am not Web Dev Simplified nor am I involved with the channel or its members in anyway).

adi518 commented 5 months ago

@MostafaKMilly It's not considered a fix if it breaks something, which is accessibility in this case. Anyway, this was fixed for v5, but not everyone can just jump to the next major version. See https://github.com/mui/material-ui/pull/35735.