diff --git a/packages/docs/src/examples/v-carousel/prop-mousewheel.vue b/packages/docs/src/examples/v-carousel/prop-mousewheel.vue
new file mode 100644
index 00000000000..c8bcecf0fbe
--- /dev/null
+++ b/packages/docs/src/examples/v-carousel/prop-mousewheel.vue
@@ -0,0 +1,20 @@
+
+
+
+
+ Slide {{ i + 1 }}
+
+
+
+
+
+
diff --git a/packages/docs/src/pages/en/components/carousels.md b/packages/docs/src/pages/en/components/carousels.md
index 58cae914219..d6dc5b2dcf6 100644
--- a/packages/docs/src/pages/en/components/carousels.md
+++ b/packages/docs/src/pages/en/components/carousels.md
@@ -87,6 +87,12 @@ You can show a linear progress bar with the **progress** prop. It will indicate
+#### Mousewheel
+
+Enable mouse-wheel (and trackpad scroll) navigation with the **mousewheel** prop. Scrolling down or right advances to the next slide; scrolling up or left goes to the previous one. A 300ms cooldown prevents accidental multi-slide jumps per scroll gesture.
+
+
+
#### Model
You can control carousel with **v-model**.
diff --git a/packages/vuetify/src/components/VCarousel/VCarousel.tsx b/packages/vuetify/src/components/VCarousel/VCarousel.tsx
index f20401b8c9d..db6ed524f71 100644
--- a/packages/vuetify/src/components/VCarousel/VCarousel.tsx
+++ b/packages/vuetify/src/components/VCarousel/VCarousel.tsx
@@ -13,8 +13,8 @@ import { useLocale } from '@/composables/locale'
import { useProxiedModel } from '@/composables/proxiedModel'
// Utilities
-import { nextTick, onMounted, ref, watch } from 'vue'
-import { convertToUnit, genericComponent, propsFactory, useRender } from '@/util'
+import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
+import { convertToUnit, genericComponent, IN_BROWSER, propsFactory, useRender } from '@/util'
// Types
import type { PropType } from 'vue'
@@ -40,6 +40,7 @@ export const makeVCarouselProps = propsFactory({
default: 6000,
validator: (value: string | number) => Number(value) > 0,
},
+ mousewheel: Boolean,
progress: [Boolean, String],
verticalDelimiters: [Boolean, String] as PropType,
@@ -105,6 +106,41 @@ export const VCarousel = genericComponent(
window.requestAnimationFrame(startTimeout)
}
+ let lastWheelAt = 0
+ function onWheel (e: WheelEvent) {
+ e.preventDefault()
+ const now = Date.now()
+ if (now - lastWheelAt < 300 || !windowRef.value) return
+ lastWheelAt = now
+ if (e.deltaY > 0 || e.deltaX > 0) {
+ windowRef.value.group.next()
+ } else {
+ windowRef.value.group.prev()
+ }
+ }
+
+ watch(() => props.mousewheel, val => {
+ if (!IN_BROWSER || !windowRef.value) return
+ const el: HTMLElement = windowRef.value.$el
+ if (val) {
+ el.addEventListener('wheel', onWheel, { passive: false })
+ } else {
+ el.removeEventListener('wheel', onWheel)
+ }
+ })
+
+ onMounted(() => {
+ if (props.mousewheel && windowRef.value) {
+ windowRef.value.$el.addEventListener('wheel', onWheel, { passive: false })
+ }
+ })
+
+ onBeforeUnmount(() => {
+ if (windowRef.value) {
+ windowRef.value.$el.removeEventListener('wheel', onWheel)
+ }
+ })
+
function onDelimiterKeyDown (e: KeyboardEvent, group: GroupProvide) {
if (
(props.direction === 'horizontal' && e.key === 'ArrowLeft') ||