Kris Rice
Kris Rice

Reputation: 723

How do I get a NextUI ListBox to scroll to the last ListItem?

Some background, I'm attempting to create a message chat feed.

I have a NextUI ListBox component that has the property isVirtualized and the appropriate params. It is created using the following:

    <>
        <h1>{selectedServer ? selectedServer.serverAlias : "Chat Title"}</h1>
        <ListboxWrapper ref={containerRef}>
            <Listbox
                isVirtualized
                aria-label="Dynamic Actions"
                items={chats}
                selectedKeys={selectedKeys}
                selectionMode="none"
                onSelectionChange={setSelectedKeys}
                virtualization={{
                    maxListboxHeight: 600,
                    itemHeight: 40,
                }}
            >
                {(item) => (
                    <ListboxItem key={item.id}>
                        {item.text}
                    </ListboxItem>
                )}
            </Listbox>
        </ListboxWrapper>

        <Input
            label="Send Message"
            type={selectedServer ? "text" : "hidden"}
            raduis={"full"}
            onKeyUp={onKeyPressHandler}
            value={textValue}
            onChange={onChangeHandler}
        />
    </>

And the ListboxWrapper:

const ListboxWrapper = ({children}) => (
    <div className="grid row-span-6 w-full h-full border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
        {children}
    </div>
);

The items of the list are loaded dynamically. I would like the last item in the list to always be at the bottom of the containing div.

I currently have:

const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({behavior: 'smooth' , block: 'end'})
}

Which scrolls to the top. It doesn't seem to matter what block I set (end or start), the behaviour is the same. Am I doing something wrong or is there an easier way to do this?

I had the same results with document.getElementById(..).scrollIntoView(..). I also moved the ref to the last list item, but when I do that, the last list item appears at the top of the container and the other items are not visible and cannot be scrolled.

Thanks in advanced!

UPDATE:

I tried the solution suggested below but same behaviour.

It seems whenever I type text into the input box, the ListBox scrolls to the top. I have updated the code above to include the full return of the component.

The onKeyPressHandler and onChangeHandler functions with their hooks:

const [selectedKeys, setSelectedKeys] = React.useState(new Set(["text"]));
const selectedValue = React.useMemo(() => Array.from(selectedKeys).join(", "), [selectedKeys]);

const onKeyPressHandler = e => {
    if (e.key === "Enter") {
        const message = new ApiCall()
        const chatRequest = new ChatRequest()
        chatRequest.setChattext(textValue)
        chatRequest.setServerid(selectedServer.serverID)
        message.setChatrequest(chatRequest)
        const apiCall = message.serializeBinary()

        const requestOptions = {
            method: 'POST',
            headers: {'Content-Type': 'application/x-protobuf'},
            body: apiCall
        };

        console.log("fetching chats")
        fetch('http://localhost:8080/api/chats', requestOptions)
            .then(response => {
                if (response.ok) {
                    getChats()
                }

                changeTextValue("");
            })
    }
};

const onChangeHandler = e => {
    changeTextValue(e.target.value);
};

And finally, the getChats function, that gets the chats from the backend and calls scrollToBottom when its complete:

const getChats = () => {
    fetch("http://localhost:8080/api/chats?serverID=" + selectedServer.serverID)
        .then(res => res.json())
        .then(data => {
            setChats(data);
            scrollToBottom()
        })
}

UPDATE2:

I added a console.log to the scrollToBottom function and it is only being called when the chats are updated. However, it isn't scrolling. Every time I type anything into the input box, the list scrolls to the top, almost like it is being redrawn?

UPDATE3:

I went back to the drawing board and did some research into grid and flex layouts. I have also switched from using the virtualised scroll that comes with ListBox to css scrolling using overflow, making the answer below work.

Upvotes: 1

Views: 67

Answers (0)

Related Questions