Skip to content

feat: add smooth keyboard scroll support#519

Open
realhardik wants to merge 1 commit into
darkroomengineering:mainfrom
realhardik:feat/smooth-keyboard-scroll
Open

feat: add smooth keyboard scroll support#519
realhardik wants to merge 1 commit into
darkroomengineering:mainfrom
realhardik:feat/smooth-keyboard-scroll

Conversation

@realhardik

Copy link
Copy Markdown

Summary

Adds smooth-scrolled keyboard navigation to Lenis. Currently Lenis handles wheel and touch events but completely ignores keyboard input — keyboard-only users get native jerky scroll while mouse/trackpad users get buttery smooth scroll. This closes that accessibility gap.

Closes issue #518

New option

new Lenis({
  smoothKeyboard: true, // default, opt-out with false
})

Keys handled

Key Behavior
ArrowUp / ArrowDown ±100px scroll (vertical / gestureOrientation: 'both')
ArrowLeft / ArrowRight ±100px scroll (horizontal / gestureOrientation: 'both')
Space Scroll by viewport height (minus 40px)
Shift+Space Reverse of Space
PageUp / PageDown Same as Space
Home Smooth scroll to start
End Smooth scroll to end
Tab Never intercepted — accessibility preserved

Safety checks

  • Skips <input>, <textarea>, <select>, contentEditable elements
  • Respects data-lenis-prevent on focused element
  • Respects prevent() and virtualScroll() callbacks
  • Orientation-aware via gestureOrientation (vertical / horizontal / both)
  • Emits virtual-scroll event for keyboard actions
  • Checks isStopped / isLocked state

Files changed

  • packages/core/src/types.ts — Added smoothKeyboard to LenisOptions, KeyboardEvent to VirtualScrollData
  • packages/core/src/lenis.tsonKeyDown handler, isEditableElement helper, lifecycle setup/teardown

Non-breaking

  • smoothKeyboard defaults to true but can be disabled
  • No changes to existing wheel/touch behavior
  • Build passes clean

Add smoothKeyboard option (default: true) that enables smooth-scrolled
keyboard navigation — ArrowUp/Down/Left/Right, Space, PageUp/Down, Home, End.

Keys are orientation-aware (gestureOrientation: both/vertical/horizontal),
skip editable elements (input/textarea/select/contentEditable), respect
data-lenis-prevent and prevent/virtualScroll callbacks, and never intercept Tab.

Closes the accessibility gap where wheel users get smooth scroll but
keyboard-only users get native jerky scroll.
@realhardik realhardik requested a review from a team as a code owner May 26, 2026 18:52
@realhardik realhardik requested review from Mekwek and vanvasten May 26, 2026 18:52
@vercel

vercel Bot commented May 26, 2026

Copy link
Copy Markdown

@realhardik is attempting to deploy a commit to the Darkroom Open Source Team on Vercel.

A member of the Team first needs to authorize it.

@clementroche

clementroche commented Jun 1, 2026

Copy link
Copy Markdown
Member

Why ±100px from arrows, is this an arbitrary value, where does it come from?

@realhardik

Copy link
Copy Markdown
Author

Why ±100px from arrows, is this an arbitrary value, where does it come from?

±100 is based on the deltaY value Chrome commonly produces for a single wheel notch in pixel mode. It also felt like a reasonable since 50 seemed too slow, while 200 felt too fast. Using 100 keeps keyboard scrolling roughly aligned with wheel scrolling while maintaining a comfortable navigation speed.

@clementroche

Copy link
Copy Markdown
Member

On my macbook this value is 40px so i'm wondering if there is a way to get the correct value on every machine.

@realhardik

realhardik commented Jun 1, 2026

Copy link
Copy Markdown
Author

On my macbook this value is 40px so i'm wondering if there is a way to get the correct value on every machine.

The 100px i mentioned is standard from the wheel event. What you might have checked is value from arrow event. (I was trying to match arrow's speed with standard scroll speed)
And yea we can hardcode that value too but there isn't any direct API that provides correct value for every machine.

But, If you want consistency across devices, we can multiply a constant with viewport's height to let's say scroll 10% of screen on every arrow key event. Let me know if you like that approach.

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