8

Some answers of our chatbot are very long. The webchat scrolls automatically to the bottom so users have to scroll up to get to the top of the bubble and start reading.

I've implemented a custom renderer (react) to wrap the answers into a custom component which simply wraps the answer into a div-tag. I also implemented a simple piece of code to scroll to the top of the bubble.

const MyCustomActivityContainer = ({ children }) => {
    const triggerScrollTo = () => {
        if (scrollRef && scrollRef.current) {
            (scrollRef.current as any).scrollIntoView({
                behavior: 'smooth',
                block: 'start',
            })
        }
    }

    const scrollRef: React.RefObject<HTMLDivElement> = React.createRef()

    return (
        <div ref={ scrollRef } onClick={ triggerScrollTo }>
            { children }
        </div>
    )
}

export const activityMiddleware = () => next => card => {
    if (/* some conditions */) {
        return (
            <MyCustomActivityContainer>
                { next(card) }
            </MyCustomActivityContainer>
        );
    } else {
        return (
            { next(card) }
        )
    }
};

But this only works if the scrollbar slider is not at its lowest position (there is at least 1 pixel left to scroll down, see here). The problem is the useScrollToBottom hook which always scrolls to bottom automatically if the scrollbar is completely scrolled down.

Is there any way to overwrite the scroll behavior or to temporarily disable the scrollToBottom feature?

KyleMit
  • 30,350
  • 66
  • 462
  • 664
MrToast
  • 1,159
  • 13
  • 41
  • 2
    If you could add a reproducible demo of your problem, it might help people provide a solution. without it, it seems like a very broad question – Shubham Khatri May 05 '20 at 09:28
  • 2
    @KyleMit, I read this post deeply, also, read the given open issue on GitHub. if it is possible, please post a re-production of your issue on somewhere like CodeSandBox. definitely, we can help you better. – AmerllicA May 05 '20 at 21:53
  • Thanks for all the replies. I'm very busy at work and at home but I try to provide a minimal working example that shows the issue, hopefully in the next week. – MrToast May 08 '20 at 10:40

2 Answers2

2

As there is no reproducible example I can only guess.
And I'll have to make some guesses on the question too.
Because it's not clear what exactly in not working:

  1. Do you mean that click on the <div> of MyCustomActivityContainer and subsequent call to triggerScrollTo doesn't result into a scroll? That would be strange, but who knows. In this case I doubt anyone will help you without reproducible example.
  2. Or do you mean that you can scroll the message into view, but if it is already in the view then new messages can result into a scroll while user is still reading a message.
    That's so, but it contradicts with you statement that your messages are very long, because that would be the problem with short messages, not with the long ones.

    But anyway, you should be able to fix that.
    If it works fine with 1 pixel off the lowest position, then just scroll that 1 pixel. You'll need to find the scrollable element. And do scrollable_element.scrollTop -= 1. I tested this approach here. And it worked (there the scrollable element is the grandparent of <p>'s)

  3. Or do you try to scroll automatically at the moment the message arrives? Аnd that is the real issue, but you forgot to mention it, and didn't posted the code that tries to auto-scroll?

    In that case you can try to use setTimeout() and defer the scroll by, let's say, 200ms. This number in based on what I gathered from the source:

    1. BotFramework-WebChat uses react-scroll-to-bottom
    2. In react-scroll-to-bottom there are some timeouts 100ms and 34ms
    3. BotFramework-WebChat doesn't redefine them
    4. There are some heuristics in react-scroll-to-bottom that probably coursing the trouble https://github.com/compulim/react-scroll-to-bottom/blob/3eb21bc469ee5f5095a431ac584be29a0d2da950/packages/component/src/ScrollToBottom/Composer.js

      Currently, there are no reliable way to check if the "scroll" event is trigger due to user gesture, programmatic scrolling, or Chrome-synthesized "scroll" event to compensate size change. Thus, we use our best-effort to guess if it is triggered by user gesture, and disable sticky if it is heading towards the start direction.

      And
      https://github.com/compulim/react-scroll-to-bottom/blob/f19b14d6db63dcb07ffa45b4433e72284a9d53b6/packages/component/src/ScrollToBottom/Composer.js#L91

      For what we observed, #1 is fired about 20ms before #2. There is a chance that this stickyCheckTimeout is being scheduled between 1 and 2. That means, if we just look at #1 to decide if we should scroll, we will always scroll, in oppose to the user's intention.

      That's why I think you should use setTimeout()

x00
  • 13,643
  • 3
  • 16
  • 40
2

Since there isn't a reproducible code for me tweak and show you. My suggestion is tweak your code slightly. Chatbot requires constant streaming of data when a new message arrives calculate the height of the div element created for the message. If the div element is greater than the widget height scroll to the top else you can choose to leave it as it is.

Prashanth M
  • 326
  • 1
  • 7