Skip to content

feat(js): replace custom auto-scroll with use-stick-to-bottom#195

Merged
gadenbuie merged 10 commits intomainfrom
feat/use-stick-to-bottom
Apr 13, 2026
Merged

feat(js): replace custom auto-scroll with use-stick-to-bottom#195
gadenbuie merged 10 commits intomainfrom
feat/use-stick-to-bottom

Conversation

@gadenbuie
Copy link
Copy Markdown
Collaborator

@gadenbuie gadenbuie commented Apr 13, 2026

Screen.Recording.2026-04-13.at.1.19.35.PM.mov
Streaming Static
image image

Summary

  • Replace the custom useAutoScroll hook with the use-stick-to-bottom library by StackBlitz Labs, which uses ResizeObserver and velocity-based spring animation for smoother, more reliable auto-scrolling during streaming.
  • Add a floating "scroll to bottom" button that appears when the user scrolls up, with a spinning gradient border animation during active streaming (customizable via --shiny-chat-streaming-color).
  • Simplify ChatContainer by removing the custom scroll detection, IntersectionObserver sentinel, and direction-based re-engage logic in favor of the library's isAtBottom / scrollToBottom API.

Verification

  1. Open any chat app and send a message — the chat should auto-scroll to new content.
  2. Scroll up during a streaming response — a circular "scroll to bottom" button with a spinning gradient border should appear centered above the input.
  3. Click the button — it should smoothly scroll to the bottom and disappear.
  4. After the response finishes, the button border animation should stop (if still visible).
  5. The --shiny-chat-streaming-color CSS variable can be overridden to customize the gradient colors.

Replace the hand-rolled useAutoScroll hook in the chat container with
the use-stick-to-bottom library by StackBlitz Labs. The library uses
ResizeObserver and velocity-based spring animation for smoother
stick-to-bottom behavior during streaming.

- Switch from StickToBottom component to useStickToBottom hook so the
  chat input stays outside the scroll container (preserving the 2-row
  CSS grid layout)
- Add a centered "scroll to bottom" button that appears when the user
  scrolls away, with a spinning border indicator during streaming
- Add breathing room (--shiny-chat-messages-padding-bottom) between
  the last message and the chat input
- Replace IntersectionObserver shadow detection with isAtBottom from
  the library
- Add ResizeObserver mock to vitest setup for jsdom compatibility
- Update integration tests to match new scroll management behavior

The existing useAutoScroll hook is preserved for the standalone
MarkdownStream component.
…ing streaming

Use the Shiny pulse gradient (indigo → purple → pink) as a rotating
border on the scroll-to-bottom button while the assistant is streaming.
Customizable via --shiny-chat-streaming-color CSS variable.
…rver mock

- Add -webkit-mask alongside mask for Safari/iOS compatibility on the
  streaming gradient border
- Remove IntersectionObserver mock from vitest setup — no longer used
  after replacing the sentinel with isAtBottom from use-stick-to-bottom
@gadenbuie gadenbuie marked this pull request as ready for review April 13, 2026 17:02
@gadenbuie gadenbuie requested a review from cpsievert April 13, 2026 17:02
The use-stick-to-bottom integration added wrapper divs around the
messages area, breaking the `> .shiny-chat-messages` direct-child
selector. Update `loc_messages` to target `.shiny-chat-messages-content`
and add `loc_scroll_container` for the scrollable `.shiny-chat-messages`
element.
- Add aria-hidden="true" to chevronDown SVG icon
- Add prefers-reduced-motion media query to disable spin animation
- Add :focus-visible outline for keyboard users
- Increase button padding from 6px to 8px for better target size (32x32)
- Use overflow:clip instead of overflow:hidden on wrapper to avoid
  clipping focus rings
Copy link
Copy Markdown
Collaborator

@cpsievert cpsievert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@gadenbuie gadenbuie merged commit dfabd6e into main Apr 13, 2026
17 checks passed
@gadenbuie gadenbuie deleted the feat/use-stick-to-bottom branch April 13, 2026 20:07
JamesHWade added a commit to JamesHWade/shinychat that referenced this pull request Apr 14, 2026
Incorporates three upstream changes:
- fix(pkg-py): serialize HTMLDependency in field serializers for bookmarking (posit-dev#189)
- fix(pkg-py): re-send HTMLDependency objects on bookmark restore (posit-dev#191)
- feat(js): replace custom auto-scroll with use-stick-to-bottom (posit-dev#195)

Resolved conflicts in icons.ts (kept dowshinychat icons + upstream chevronDown),
CHANGELOG.md (merged both sections), and rebuilt JS assets from source.
Updated new test file imports from shinychat to dowshinychat.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants