Skip to content

Carousel's keyboard handler hardcodes ArrowLeft/ArrowRight regardless of orientation="vertical", unlike every other orientation-aware part of the component #8308

Description

@JSONbored

Context

packages/loopover-ui-kit/src/components/carousel.tsx's Carousel component accepts an orientation?: "horizontal" | "vertical" prop, and every other piece of the component branches on it: CarouselContent switches between -ml-4 (horizontal) and -mt-4 flex-col (vertical); CarouselItem switches between pl-4 and pt-4; CarouselPrevious/CarouselNext reposition themselves (left/right vs. top/bottom) and rotate 90 degrees for the vertical layout.

The component's keyboard handler does not follow this pattern. handleKeyDown (lines 86-97) is registered unconditionally regardless of orientation and only ever responds to ArrowLeft/ArrowRight:

const handleKeyDown = React.useCallback(
  (event: React.KeyboardEvent<HTMLDivElement>) => {
    if (event.key === "ArrowLeft") {
      event.preventDefault();
      scrollPrev();
    } else if (event.key === "ArrowRight") {
      event.preventDefault();
      scrollNext();
    }
  },
  [scrollPrev, scrollNext],
);

For a orientation="vertical" carousel — whose CarouselPrevious/CarouselNext buttons are already visually rotated to point up/down — ArrowUp/ArrowDown do nothing, while ArrowLeft/ArrowRight (which have no on-screen meaning in the vertical layout) still scroll the carousel. This is a real keyboard-interaction inconsistency, not just a visual one: a keyboard user operating a vertical carousel gets no working arrow-key navigation that matches what they see.

Requirements

  • Make handleKeyDown orientation-aware: when orientation === "vertical", respond to ArrowUp/ArrowDown (mapping ArrowUpscrollPrev(), ArrowDownscrollNext()); when orientation === "horizontal" (the default), keep the existing ArrowLeft/ArrowRightscrollPrev()/scrollNext() mapping.
  • Use the same orientation resolution the component already computes for CarouselContext (orientation || (opts?.axis === "y" ? "vertical" : "horizontal")), not a second, independent orientation check.
  • Do not change scrollPrev/scrollNext, the Embla wiring, or any non-keyboard behavior.

Deliverables

  • handleKeyDown in packages/loopover-ui-kit/src/components/carousel.tsx branches on the resolved orientation and binds ArrowUp/ArrowDown for vertical carousels, ArrowLeft/ArrowRight for horizontal (the current, unchanged default)
  • A regression test rendering a Carousel with orientation="vertical" and asserting ArrowDown/ArrowUp key events call the underlying Embla scrollNext/scrollPrev, and that ArrowLeft/ArrowRight do not trigger scrolling in that mode
  • An existing or new test confirming the current horizontal-mode behavior (ArrowLeft/ArrowRight) is unchanged

Test Coverage Requirements

packages/loopover-ui-kit is not in the root vitest.config.ts's coverage.include and is not Codecov-gated — still add the tests above per this package's own "suite must run and pass" acceptance bar (packages/loopover-ui-kit/vitest.config.ts). carousel.tsx currently has zero existing test coverage; this issue's regression test is also this component's first.

Expected Outcome

A Carousel rendered with orientation="vertical" responds to ArrowUp/ArrowDown for keyboard navigation, matching the orientation-aware layout its CarouselContent/CarouselItem/CarouselPrevious/CarouselNext siblings already provide, instead of silently doing nothing for vertical keyboard users.

Links & Resources

  • packages/loopover-ui-kit/src/components/carousel.tsx:86-97 (the ungated handler)
  • packages/loopover-ui-kit/src/components/carousel.tsx:121-128 (the existing orientation resolution logic to reuse)
  • packages/loopover-ui-kit/src/components/carousel.tsx:195-220 (CarouselPrevious, showing the orientation-aware positioning/rotation the keyboard handling should match)

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions