Skip to content

feat(VInfiniteCarousel): add new component - #23116

Open
J-Sek wants to merge 26 commits into
devfrom
feat/v-infinite-carousel
Open

feat(VInfiniteCarousel): add new component#23116
J-Sek wants to merge 26 commits into
devfrom
feat/v-infinite-carousel

Conversation

@J-Sek

@J-Sek J-Sek commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Carousel that loops over

  • uses WAAPI instead of plain CSS
  • suitable as marquee, for logos and decoration
  • supports dragging, arrows, direction, gap, separators, keyboard navigation within, etc.
  • immune to scrolling issues (wheel and focus) thanks to overflow: clip

The behavior will be hard to pull in regular carousel - will bloat that simple variant. Better to ship a separate one.

Quick demo:

<template>
  <v-app :theme="light ? 'light' : 'dark'">
    <v-app-bar title="VInfiniteCarousel">
      <v-switch v-model="light" class="mr-4" label="light theme" hide-details />
      <v-switch v-model="pause" class="mr-4" label="pause" hide-details />
      <v-switch v-model="reverse" class="mr-4" label="reverse" hide-details />
      <v-select
        v-model="showArrows"
        :items="[false, true, 'hover']"
        class="mr-4"
        label="show-arrows"
        max-width="140"
        hide-details
      />
      <v-select
        v-model="maskSize"
        :items="[0, 40, 80]"
        class="mr-4"
        label="mask"
        max-width="140"
        hide-details
      />
      <v-select
        v-model="shiftDistance"
        :items="['100%', '50%', 200, '10rem']"
        class="mr-4"
        label="shift-distance"
        max-width="140"
        hide-details
      />
      <v-switch
        :model-value="isRtl"
        class="mr-4"
        label="rtl"
        hide-details
        @update:model-value="rtl[current] = !!$event"
      />
      <v-chip class="mr-4">isRtl: {{ isRtl }}</v-chip>
    </v-app-bar>

    <v-main>
      <v-container>
        <v-sheet class="mb-12" rounded>
          <v-infinite-carousel
            :mask="maskSize"
            :paused="pause"
            :reverse="reverse"
            :shift-distance="shiftDistance"
            :show-arrows="showArrows"
            class="py-4"
            gap="1rem"
            draggable
          >
            <v-chip v-for="item in items" :key="item" color="primary">
              {{ item }}
            </v-chip>
          </v-infinite-carousel>
        </v-sheet>

        <div class="d-flex ga-8 mb-12">
          <v-sheet height="300" width="220" rounded>
            <v-infinite-carousel
              :mask="maskSize"
              :paused="pause"
              :reverse="reverse"
              :shift-distance="shiftDistance"
              :show-arrows="showArrows"
              direction="vertical"
              draggable
              wheel
            >
              <v-chip v-for="item in items" :key="item" color="primary" block>
                {{ item }}
              </v-chip>
            </v-infinite-carousel>
          </v-sheet>

          <v-sheet class="align-self-start flex-grow-1" rounded>
            <v-infinite-carousel
              :mask="maskSize"
              :paused="pause"
              :reverse="reverse"
              :shift-distance="shiftDistance"
              :show-arrows="showArrows"
              class="py-4"
              draggable
            >
              <v-chip color="info" label>only</v-chip>
              <v-chip color="warning" label>three</v-chip>
              <v-chip color="success" label>chips</v-chip>
            </v-infinite-carousel>
          </v-sheet>
        </div>

        <v-infinite-carousel
          :mask="maskSize"
          :paused="pause"
          :reverse="reverse"
          :shift-distance="shiftDistance"
          :show-arrows="showArrows"
          gap="2.5rem"
          style="user-select: none"
          wheel
        >
          <template #separator>
            <v-icon color="primary" icon="mdi-circle-small" />
          </template>

          <span
            v-for="item in items"
            :key="item"
            class="text-headline-small text-uppercase font-weight-bold font-italic opacity-50"
          >{{ item }}</span>
        </v-infinite-carousel>
      </v-container>
    </v-main>
  </v-app>
</template>

<script setup lang="ts">
  import { ref } from 'vue'
  import { useLocale, useRtl } from 'vuetify'

  const { current, rtl } = useLocale()
  const { isRtl } = useRtl()

  const light = ref(false)
  const pause = ref(false)
  const reverse = ref(false)
  const showArrows = ref<boolean | 'hover'>('hover')
  const maskSize = ref(40)
  const shiftDistance = ref<string | number>('50%')

  const items = Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`)
</script>

@J-Sek J-Sek self-assigned this Aug 13, 2026
@J-Sek J-Sek added the C: New Component This issue would need a new component to be developed. label Aug 13, 2026
@J-Sek J-Sek added this to the v4.x.x milestone Aug 13, 2026
@J-Sek
J-Sek force-pushed the feat/v-infinite-carousel branch from de024cc to 95a581b Compare August 19, 2026 11:15
@J-Sek
J-Sek force-pushed the feat/v-infinite-carousel branch from 95a581b to 77ae141 Compare August 19, 2026 11:50
@J-Sek
J-Sek force-pushed the feat/v-infinite-carousel branch from 74a59b6 to 4facbeb Compare September 11, 2026 15:09
@J-Sek
J-Sek force-pushed the feat/v-infinite-carousel branch from 53ec2ad to 9033d69 Compare September 11, 2026 16:03
@J-Sek
J-Sek marked this pull request as ready for review September 11, 2026 16:03
@J-Sek J-Sek modified the milestones: v4.x.x, v4.3.0 Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C: New Component This issue would need a new component to be developed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant