Skip to content

fix: add desktop drag scrolling for horizontal rows#98

Open
AlejandroAkbal wants to merge 1 commit intomainfrom
auto-triage/270-feature-scroll-horizontally-on-desktop-by-click-dragging-or-with-scrolling
Open

fix: add desktop drag scrolling for horizontal rows#98
AlejandroAkbal wants to merge 1 commit intomainfrom
auto-triage/270-feature-scroll-horizontally-on-desktop-by-click-dragging-or-with-scrolling

Conversation

@AlejandroAkbal
Copy link
Member

@AlejandroAkbal AlejandroAkbal commented Mar 14, 2026

Summary

  • add shared desktop-only horizontal scroll behavior for overflowing rows so normal mouse wheel scrolls sideways without breaking touchpad/native horizontal gestures
  • enable click-drag scrolling for the featured tags row and search filters row on desktop while suppressing accidental clicks after dragging
  • preserve normal page scrolling at row boundaries and keep the change scoped to the two existing horizontal containers

Validation

  • pnpm install
  • pnpm exec nuxi typecheck (fails due to pre-existing repo-wide baseline errors unrelated to this change)
  • pnpm exec nuxi prepare

Feedback issue: https://feedback.r34.app/posts/270/feature-scroll-horizontally-on-desktop-by-click-dragging-or-with-scrolling

Summary by CodeRabbit

  • New Features
    • Featured tags section now supports horizontal scrolling with drag-to-scroll and mouse wheel input.
    • Search filters now support horizontal scrolling with drag-to-scroll and mouse wheel input.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 14, 2026

Walkthrough

A new composable hook useDesktopHorizontalScroll is introduced to enable desktop horizontal scrolling with drag-to-scroll and mouse wheel support. This hook is then applied to two components to handle horizontal scrolling of featured tags and search filter rows.

Changes

Cohort / File(s) Summary
New Horizontal Scroll Composable
composables/useDesktopHorizontalScroll.ts
New composable providing desktop horizontal scrolling functionality. Manages pointer events for drag-to-scroll, mouse wheel input handling, drag threshold detection, and click suppression post-drag. Uses VueUse's useEventListener for wheel, pointer, and capture-phase click events.
Components Using Scroll Behavior
components/pages/home/FeaturedTags.vue, components/pages/posts/navigation/search/SearchMenu.vue
Added template refs and invocations of useDesktopHorizontalScroll to enable horizontal scrolling on the featured tags list and filters row respectively.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Component as Vue Component
    participant Composable as useDesktopHorizontalScroll
    participant EventSystem as Event Listeners

    User->>EventSystem: Move mouse/wheel on element
    EventSystem->>Composable: Trigger wheel/pointer events
    Composable->>Composable: Track drag state (position, threshold)
    Composable->>Composable: Calculate scroll offset
    Composable->>Component: Update container scrollLeft
    Component->>Component: Re-render with new scroll position
    Component-->>User: Display updated scroll view
    
    User->>EventSystem: Click after drag
    EventSystem->>Composable: pointerup/click event
    Composable->>EventSystem: Suppress click if drag occurred
    EventSystem-->>User: Click action prevented
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: introducing desktop drag scrolling functionality for horizontal rows, which matches the composable implementation and its application to FeaturedTags and SearchMenu components.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch auto-triage/270-feature-scroll-horizontally-on-desktop-by-click-dragging-or-with-scrolling
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch auto-triage/270-feature-scroll-horizontally-on-desktop-by-click-dragging-or-with-scrolling
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@composables/useDesktopHorizontalScroll.ts`:
- Around line 20-41: Update the wheel handler in useDesktopHorizontalScroll (the
function that checks isLikelyMouseWheel and currently does
event.preventDefault() before horizontal scrolling) to early-return when the
wheel is being used as a zoom gesture by checking event.ctrlKey (and optionally
event.metaKey for macOS); add this check to the existing early-return
condition(s) so zoom (Ctrl+wheel) is not blocked before calling
event.preventDefault() and the horizontal scroll logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1423d4cc-d47c-4103-b8ad-2adfa605e56e

📥 Commits

Reviewing files that changed from the base of the PR and between 5cc34fe and 514691a.

📒 Files selected for processing (3)
  • components/pages/home/FeaturedTags.vue
  • components/pages/posts/navigation/search/SearchMenu.vue
  • composables/useDesktopHorizontalScroll.ts

Comment on lines +20 to +41
// Preserve touchpad/native horizontal behavior and only map normal mouse wheel.
if (event.deltaX !== 0 || event.deltaY === 0 || !isLikelyMouseWheel(event)) {
return
}

const maxScrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth

if (maxScrollLeft <= 0) {
return
}

const canScrollLeft = scrollContainer.scrollLeft > 0
const canScrollRight = scrollContainer.scrollLeft < maxScrollLeft

if ((event.deltaY < 0 && !canScrollLeft) || (event.deltaY > 0 && !canScrollRight)) {
return
}

event.preventDefault()

scrollContainer.scrollLeft += event.deltaY
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In browser wheel event handling, does preventDefault() on a wheel event with ctrlKey=true suppress page zoom behavior?

💡 Result:

Yes—when the wheel event is cancelable and your listener is non-passive, calling event.preventDefault() on a wheel event with ctrlKey === true suppresses the browser’s default page-zoom (Ctrl+wheel / trackpad-pinch-zoom) behavior. MDN notes that zoom gestures fire wheel events with ctrlKey set, and that canceling the event prevents “scrolling or zooming.” [1]

Practical requirements / caveats:

  • Register the listener with { passive: false }, otherwise the browser may ignore preventDefault() for performance reasons. [1]
  • Some browsers may make only the first event in a wheel sequence cancelable (later events can be non-cancelable), and non-cancelable events can’t be prevented. [1], [2]
  • Chromium explicitly changed behavior so Ctrl+wheel goes to the page first and only triggers browser zoom if unhandled (i.e., not prevented). [3]

Sources: [1] MDN wheel event docs, [2] W3C Wheel Events spec, [3] Chromium blink-dev “ctrl+mousewheel events can now be overridden”.


🏁 Script executed:

fd -t f "useDesktopHorizontalScroll.ts"

Repository: Rule-34/App

Length of output: 96


🏁 Script executed:

cat -n composables/useDesktopHorizontalScroll.ts

Repository: Rule-34/App

Length of output: 4317


Add early return for zoom gestures (Ctrl+wheel) in wheel handler.

The wheel event listener at line 113 is registered with { passive: false }, which means event.preventDefault() at line 38 will effectively suppress browser default behavior. Without checking event.ctrlKey first, this prevents page zoom when using Ctrl+wheel. Add a check for zoom gestures to the early return condition:

Proposed patch
   // Preserve touchpad/native horizontal behavior and only map normal mouse wheel.
-  if (event.deltaX !== 0 || event.deltaY === 0 || !isLikelyMouseWheel(event)) {
+  if (event.ctrlKey || event.deltaX !== 0 || event.deltaY === 0 || !isLikelyMouseWheel(event)) {
     return
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Preserve touchpad/native horizontal behavior and only map normal mouse wheel.
if (event.deltaX !== 0 || event.deltaY === 0 || !isLikelyMouseWheel(event)) {
return
}
const maxScrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth
if (maxScrollLeft <= 0) {
return
}
const canScrollLeft = scrollContainer.scrollLeft > 0
const canScrollRight = scrollContainer.scrollLeft < maxScrollLeft
if ((event.deltaY < 0 && !canScrollLeft) || (event.deltaY > 0 && !canScrollRight)) {
return
}
event.preventDefault()
scrollContainer.scrollLeft += event.deltaY
}
// Preserve touchpad/native horizontal behavior and only map normal mouse wheel.
if (event.ctrlKey || event.deltaX !== 0 || event.deltaY === 0 || !isLikelyMouseWheel(event)) {
return
}
const maxScrollLeft = scrollContainer.scrollWidth - scrollContainer.clientWidth
if (maxScrollLeft <= 0) {
return
}
const canScrollLeft = scrollContainer.scrollLeft > 0
const canScrollRight = scrollContainer.scrollLeft < maxScrollLeft
if ((event.deltaY < 0 && !canScrollLeft) || (event.deltaY > 0 && !canScrollRight)) {
return
}
event.preventDefault()
scrollContainer.scrollLeft += event.deltaY
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@composables/useDesktopHorizontalScroll.ts` around lines 20 - 41, Update the
wheel handler in useDesktopHorizontalScroll (the function that checks
isLikelyMouseWheel and currently does event.preventDefault() before horizontal
scrolling) to early-return when the wheel is being used as a zoom gesture by
checking event.ctrlKey (and optionally event.metaKey for macOS); add this check
to the existing early-return condition(s) so zoom (Ctrl+wheel) is not blocked
before calling event.preventDefault() and the horizontal scroll logic.

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.

1 participant