Skip to content

agoudbg/scroll-slides

Repository files navigation

scroll-slides

English | 简体中文

A smooth and customizable scroll-based slide animation component for Vue 3. Create engaging scroll experiences with dynamic scaling, translation, and occlusion effects.

npm version license

✨ Features

  • 🎯 Smooth Scroll Animations - Transform items as they scroll with elegant scaling and translation effects
  • 📱 Direction Support - Both vertical and horizontal scrolling modes
  • 🎨 Highly Customizable - Fine-tune animation parameters to match your design
  • 🔄 Dynamic Item Management - Add or remove items on the fly
  • 📐 Flexible Templates - Use generic or per-item slot templates
  • 🚀 Performance Optimized - Efficient event handling and DOM updates
  • 💅 TypeScript Support - Full type definitions included
  • 🎭 Occlusion Effects - Optional lower item clipping for depth perception

📦 Installation

npm install scroll-slides
yarn add scroll-slides
pnpm add scroll-slides

🚀 Quick Start

Basic Usage

<script setup>
import { ScrollSlide } from 'scroll-slides';
</script>

<template>
  <ScrollSlide
    direction="vertical"
    :item-count="10"
    style="height: 600px; overflow-y: auto;"
  >
    <template #item="{ index }">
      <div class="slide-item">
        Slide {{ index + 1 }}
      </div>
    </template>
  </ScrollSlide>
</template>

<style scoped>
.slide-item {
  width: 100%;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-radius: 15px;
  color: white;
  margin-bottom: 10px;
}
</style>

Horizontal Scrolling

<template>
  <ScrollSlide
    direction="horizontal"
    :item-count="15"
    :scale-start-percent="0.95"
    :translate-factor="50"
    :spacer-enabled="true"
    style="width: 100%; height: 200px; overflow-x: auto;"
  >
    <template #item="{ index }">
      <div class="horizontal-item">
        Item {{ index + 1 }}
      </div>
    </template>
  </ScrollSlide>
</template>

<style scoped>
.horizontal-item {
  width: 200px;
  height: 120px;
  margin-right: 15px;
  background: #4CAF50;
  border-radius: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
}
</style>

Independent Templates

You can define unique content for each item using indexed slots:

<template>
  <ScrollSlide direction="vertical" :item-count="3">
    <template #item-0>
      <div class="custom-item">🌸 First Item</div>
    </template>
    
    <template #item-1>
      <div class="custom-item">🎨 Second Item</div>
    </template>
    
    <template #item-2>
      <div class="custom-item">🚀 Third Item</div>
    </template>
  </ScrollSlide>
</template>

📖 API Reference

Props

Prop Type Default Description
direction 'vertical' | 'horizontal' 'vertical' Scrolling direction
itemCount number 0 Total number of items in the list
scaleRatio number 0.7 Final scale of the item when it slides out (0-1)
scaleStartPercent number 0.8 Threshold percentage for scaling to start (0-1)
translateFactor number 100 Adjusts the displacement offset during slide-out
spacerEnabled boolean false Adds a spacer at start to allow first item to scroll out
occludeLowerItems boolean false Applies clip-path to prevent visual overlap

Slots

Default Item Slot

Used when no specific item slot is defined:

<template #item="{ index }">
  <!-- Your content here -->
  <!-- index: number - The zero-based index of the current item -->
</template>

Indexed Item Slots

Define unique content for specific items:

<template #item-0>
  <!-- Content for first item -->
</template>

<template #item-1>
  <!-- Content for second item -->
</template>

Note: Indexed slots take priority over the generic #item slot.

Spacer Slot

Customize the spacer element (when spacerEnabled is true):

<template #spacer="{ size }">
  <!-- size: number - The calculated size of the spacer in pixels -->
  <div>Custom Spacer Content</div>
</template>

🎨 Customization Examples

Subtle Animation

<ScrollSlide
  :scale-ratio="0.9"
  :scale-start-percent="0.95"
  :translate-factor="20"
  :item-count="10"
>
  <template #item="{ index }">
    <!-- Your content -->
  </template>
</ScrollSlide>

Dramatic Effect

<ScrollSlide
  :scale-ratio="0.5"
  :scale-start-percent="0.7"
  :translate-factor="150"
  :occlude-lower-items="true"
  :item-count="10"
>
  <template #item="{ index }">
    <!-- Your content -->
  </template>
</ScrollSlide>

Horizontal Card Carousel

<ScrollSlide
  direction="horizontal"
  :item-count="20"
  :scale-ratio="0.85"
  :scale-start-percent="0.9"
  :translate-factor="30"
  :spacer-enabled="true"
  style="width: 100%; height: 250px; overflow-x: auto;"
>
  <template #item="{ index }">
    <div class="card">
      Card {{ index + 1 }}
    </div>
  </template>
</ScrollSlide>

🔧 Advanced Usage

Dynamic Item Count

<script setup>
import { ref } from 'vue';
import { ScrollSlide } from 'scroll-slides';

const items = ref([1, 2, 3, 4, 5]);

const addItem = () => {
  items.value.push(items.value.length + 1);
};

const removeItem = () => {
  items.value.pop();
};
</script>

<template>
  <div>
    <button @click="addItem">Add Item</button>
    <button @click="removeItem">Remove Item</button>
    
    <ScrollSlide :item-count="items.length">
      <template #item="{ index }">
        <div>Item {{ items[index] }}</div>
      </template>
    </ScrollSlide>
  </div>
</template>

Responsive Configuration

<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue';
import { ScrollSlide } from 'scroll-slides';

const windowWidth = ref(window.innerWidth);

const direction = computed(() => 
  windowWidth.value < 768 ? 'vertical' : 'horizontal'
);

const updateWidth = () => {
  windowWidth.value = window.innerWidth;
};

onMounted(() => window.addEventListener('resize', updateWidth));
onUnmounted(() => window.removeEventListener('resize', updateWidth));
</script>

<template>
  <ScrollSlide
    :direction="direction"
    :item-count="10"
    :style="direction === 'vertical' 
      ? 'height: 500px; overflow-y: auto;' 
      : 'width: 100%; overflow-x: auto;'"
  >
    <template #item="{ index }">
      <!-- Responsive content -->
    </template>
  </ScrollSlide>
</template>

💡 Tips & Best Practices

  1. Container Styling: Always set explicit dimensions and overflow properties on the ScrollSlide container:

    <ScrollSlide style="height: 600px; overflow-y: auto;">
  2. Item Spacing: Add margins to your item content, not the slot wrapper:

    .my-item {
      margin-bottom: 10px; /* for vertical */
      margin-right: 10px;  /* for horizontal */
    }
  3. Performance: For large lists, consider using virtual scrolling techniques in combination with scroll-slides.

  4. Z-Index: Items are automatically z-indexed in reverse order (first item on top). Plan your designs accordingly.

  5. Spacer Usage: Enable spacerEnabled when you want the first item to be able to scroll to the center/top of the viewport.

🛠️ Development

# Clone the repository
git clone https://github.com/agoudbg/scroll-slides.git

# Install dependencies
pnpm install

# Run development server
pnpm dev

# Build library
pnpm build

# Build demo
pnpm build:demo

📄 License

MIT License - see LICENSE file for details

🤝 Contributing

Contributions, issues, and feature requests are welcome! Feel free to check the issues page.

👤 Author

agoudbg

🌟 Show Your Support

Give a ⭐️ if this project helped you!


Made with ❤️ using Vue 3 and TypeScript

About

Lightweight Vue 3 component for smooth, scroll-driven slide transitions

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors