Vue Integration
MotionRail provides a first-class Vue 3 component (SFC) with full TypeScript support.
FOUC-Free Styling Example
vue
<script setup lang="ts">
import { MotionRail } from "motionrail/vue";
import { MotionRail as MotionRailClass } from "motionrail";
import "motionrail/style.css";
import { useHead } from "#imports";
// FOUC-safe container query setup for the first carousel
const { containerName, containerQueries } = MotionRailClass.getBreakPoints({
breakpoints: [
{ columns: 1, gap: "16px" },
{ width: 768, columns: 2, gap: "16px" },
{ width: 1024, columns: 3, gap: "20px" },
],
totalItems: 8,
});
// SSR/FOUC prevention: inject containerQueries in the head
useHead({
style: [
containerName && containerQueries
? {
key: containerName,
innerHTML: containerQueries,
"data-motionrail-style": containerName,
}
: undefined,
].filter(Boolean),
});
</script>
<template>
<MotionRail
:options="{
breakpoints: [
{ columns: 1, gap: '16px' },
{ width: 768, columns: 2, gap: '16px' },
{ width: 1024, columns: 3, gap: '20px' },
],
containerName,
}"
>
<div v-for="i in [1, 2, 3, 4, 5, 6, 7, 8]" :key="i">
<!-- ...carousel item content... -->
</div>
</MotionRail>
</template>Basic Usage
vue
<script setup>
import { MotionRail } from "motionrail/vue";
import "motionrail/style.css";
const options = { breakpoints: [{ columns: 3, gap: "20px" }] };
</script>
<template>
<MotionRail :options="options">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</MotionRail>
</template>Props
options
- Type: MotionRailOptions
- Required: No
- Default:
{}
Configuration options for the carousel. See Configuration for all available options.
vue
<script setup>
const options = {
autoplay: true,
delay: 3000,
breakpoints: [
{ columns: 1, gap: "16px" },
{ width: 768, columns: 2, gap: "16px" },
],
};
</script>
<template>
<MotionRail :options="options">
<!-- items -->
</MotionRail>
</template>Template Ref Access
Use template refs to access the MotionRail instance and container:
vue
<script setup>
import { ref } from "vue";
import { MotionRail } from "motionrail/vue";
const carouselRef = ref(null);
const handleNext = () => {
carouselRef.value?.instance?.next();
};
const handlePrev = () => {
carouselRef.value?.instance?.prev();
};
</script>
<template>
<div>
<MotionRail ref="carouselRef" :options="{}">
<div>Item 1</div>
<div>Item 2</div>
</MotionRail>
<button @click="handlePrev">Previous</button>
<button @click="handleNext">Next</button>
</div>
</template>Exposed Properties
The component exposes two properties via defineExpose:
instance: The MotionRail class instance (for API methods)container: The container HTMLDivElement
vue
<script setup>
import { ref, onMounted } from "vue";
const carouselRef = ref(null);
onMounted(() => {
// Access the MotionRail instance
console.log(carouselRef.value.instance);
// Access the container element
console.log(carouselRef.value.container);
});
</script>
<template>
<MotionRail ref="carouselRef" :options="{}">
<!-- items -->
</MotionRail>
</template>Complete Example
vue
<script setup>
import { ref } from "vue";
import { MotionRail } from "motionrail/vue";
import "motionrail/style.css";
const carouselRef = ref(null);
const currentState = ref(null);
const options = {
autoplay: true,
delay: 3000,
breakpoints: [
{ columns: 1, gap: "16px" },
{ width: 768, columns: 2, gap: "16px" },
{ width: 1024, columns: 3, gap: "20px" },
],
onChange: (state) => {
currentState.value = state;
},
};
const handleNext = () => {
carouselRef.value?.instance?.next();
};
const handlePrev = () => {
carouselRef.value?.instance?.prev();
};
const handlePlay = () => {
carouselRef.value?.instance?.play();
};
const handlePause = () => {
carouselRef.value?.instance?.pause();
};
</script>
<template>
<div>
<MotionRail ref="carouselRef" :options="options" class="my-carousel">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<div>Item 4</div>
<div>Item 5</div>
</MotionRail>
<div class="controls">
<button @click="handlePrev">Previous</button>
<button @click="handleNext">Next</button>
<button @click="handlePlay">Play</button>
<button @click="handlePause">Pause</button>
</div>
<div v-if="currentState" class="state-info">
<p>Visible items: {{ currentState.visibleItemIndexes.join(", ") }}</p>
<p>Total items: {{ currentState.totalItems }}</p>
</div>
</div>
</template>Dynamic Children
The Vue component automatically calls update() when slot content changes:
vue
<script setup>
import { ref } from "vue";
import { MotionRail } from "motionrail/vue";
const items = ref(["Item 1", "Item 2", "Item 3"]);
// Define options in script setup to avoid inline object creation
const options = { breakpoints: [{ columns: 3, gap: "20px" }] };
const addItem = () => {
items.value.push(`Item ${items.value.length + 1}`);
};
const removeItem = () => {
items.value.pop();
};
</script>
<template>
<div>
<MotionRail :options="options">
<div v-for="(item, index) in items" :key="index">
{{ item }}
</div>
</MotionRail>
<button @click="addItem">Add Item</button>
<button @click="removeItem">Remove Item</button>
</div>
</template>TypeScript
Full TypeScript support with <script setup lang="ts">:
vue
<script setup lang="ts">
import { ref } from "vue";
import { MotionRail } from "motionrail/vue";
import type { MotionRailOptions, MotionRailState } from "motionrail";
const carouselRef = ref<{ instance: any; container: HTMLDivElement } | null>(
null,
);
const currentState = ref<MotionRailState | null>(null);
const options: MotionRailOptions = {
autoplay: true,
breakpoints: [{ columns: 3, gap: "20px" }],
onChange: (state: MotionRailState) => {
currentState.value = state;
},
};
const handleNext = (): void => {
carouselRef.value?.instance?.next();
};
</script>
<template>
<MotionRail ref="carouselRef" :options="options">
<div>Item 1</div>
<div>Item 2</div>
</MotionRail>
</template>Attributes
All attributes are passed to the root div element:
vue
<template>
<MotionRail
:options="{}"
class="my-carousel"
style="max-width: 1200px"
aria-label="Product carousel"
>
<!-- items -->
</MotionRail>
</template>Bundle Size
Vue integration: 1.22 kB (gzipped: 0.62 kB)
Next Steps
- Configuration - All configuration options
- API Methods - Programmatic control
- Extensions - Add more functionality