Solid.js Integration
MotionRail provides a first-class Solid.js component with full TypeScript support.
FOUC-Free Styling Example
tsx
import { Style } from "@solidjs/meta";
import { clientOnly } from "@solidjs/start";
import { MotionRail as MotionRailClass } from "motionrail";
import "motionrail/style.css";
const MotionRail = clientOnly(() =>
import("motionrail/solid").then((m) => ({ default: m.MotionRail })),
);
// 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,
});
export default function Home() {
return (
<section>
{/* FOUC prevention: container query style in head, generated dynamically */}
<Style data-motionrail-style={containerName}>{containerQueries}</Style>
<MotionRail
options={{
breakpoints: [
{ columns: 1, gap: "16px" },
{ width: 768, columns: 2, gap: "16px" },
{ width: 1024, columns: 3, gap: "20px" },
],
containerName,
}}
>
{[1, 2, 3, 4, 5, 6, 7, 8].map((i) => (
<div>{/* ...carousel item content... */}</div>
))}
</MotionRail>
</section>
);
}Basic Usage
jsx
import { MotionRail } from "motionrail/solid";
import "motionrail/style.css";
// Define options outside to prevent re-renders
const options = { breakpoints: [{ columns: 3, gap: "20px" }] };
function App() {
return (
<MotionRail options={options}>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</MotionRail>
);
}Props
options
- Type: MotionRailOptions
- Required: No
Configuration options for the carousel. See Configuration for all available options.
jsx
const options = {
autoplay: true,
delay: 3000,
breakpoints: [
{ columns: 1, gap: "16px" },
{ width: 768, columns: 2, gap: "16px" },
],
};
<MotionRail options={options}>{/* items */}</MotionRail>;ref
- Type:
(instance: MotionRailClass) => void - Required: No
Callback that receives the MotionRail instance for programmatic control.
jsx
const options = {};
function MyCarousel() {
let carousel;
const handleNext = () => {
carousel?.next();
};
return (
<>
<MotionRail ref={(instance) => (carousel = instance)} options={options}>
<div>Item 1</div>
<div>Item 2</div>
</MotionRail>
<button onClick={handleNext}>Next</button>
</>
);
}divRef
- Type:
(element: HTMLDivElement) => void - Required: No
Callback that receives the container HTMLDivElement.
jsx
const options = {};
function MyCarousel() {
let container;
return (
<MotionRail divRef={(el) => (container = el)} options={options}>
<div>Item 1</div>
<div>Item 2</div>
</MotionRail>
);
}Other Props
All other props are passed to the root div element:
jsx
const options = {};
<MotionRail
options={options}
class="my-carousel"
style={{ "max-width": "1200px" }}
aria-label="Product carousel"
>
{/* items */}
</MotionRail>;Complete Example
jsx
import { createSignal } from "solid-js";
import { MotionRail } from "motionrail/solid";
import "motionrail/style.css";
function Carousel() {
let carousel;
let container;
const [currentState, setCurrentState] = createSignal(null);
const handleNext = () => {
carousel?.next();
};
const handlePrev = () => {
carousel?.prev();
};
const handlePlay = () => {
carousel?.play();
};
const handlePause = () => {
carousel?.pause();
};
// Define options inside only when using signals (setCurrentState)
const options = {
autoplay: true,
delay: 3000,
breakpoints: [
{ columns: 1, gap: "16px" },
{ width: 768, columns: 2, gap: "16px" },
{ width: 1024, columns: 3, gap: "20px" },
],
onChange: setCurrentState,
};
return (
<div>
<MotionRail
ref={(instance) => (carousel = instance)}
divRef={(el) => (container = el)}
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 onClick={handlePrev}>Previous</button>
<button onClick={handleNext}>Next</button>
<button onClick={handlePlay}>Play</button>
<button onClick={handlePause}>Pause</button>
</div>
{currentState() && (
<div class="state-info">
<p>Visible items: {currentState().visibleItemIndexes.join(", ")}</p>
<p>Total items: {currentState().totalItems}</p>
</div>
)}
</div>
);
}SSR Support (SolidStart)
When using SSR-enabled frameworks like SolidStart, you must use clientOnly to prevent server-side rendering issues since MotionRail relies on browser APIs:
tsx
import { clientOnly } from "@solidjs/start";
import "motionrail/style.css";
const MotionRail = clientOnly(() =>
import("motionrail/solid").then((m) => ({ default: m.MotionRail })),
);
const options = {
breakpoints: [
{ columns: 1, gap: "16px" },
{ width: 768, columns: 2, gap: "16px" },
{ width: 1024, columns: 3, gap: "20px" },
],
};
export default function Home() {
return (
<MotionRail options={options}>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</MotionRail>
);
}Dynamic Children
The Solid component automatically calls update() when children change:
jsx
import { createSignal, For } from "solid-js";
import { MotionRail } from "motionrail/solid";
// Define options outside to prevent re-renders
const options = { breakpoints: [{ columns: 3, gap: "20px" }] };
function DynamicCarousel() {
const [items, setItems] = createSignal(["Item 1", "Item 2", "Item 3"]);
const addItem = () => {
setItems([...items(), `Item ${items().length + 1}`]);
};
const removeItem = () => {
setItems(items().slice(0, -1));
};
return (
<>
<MotionRail options={options}>
<For each={items()}>{(item) => <div>{item}</div>}</For>
</MotionRail>
<button onClick={addItem}>Add Item</button>
<button onClick={removeItem}>Remove Item</button>
</>
);
}TypeScript
Full TypeScript support is included:
tsx
import { createSignal } from "solid-js";
import { MotionRail } from "motionrail/solid";
import type { MotionRailOptions, MotionRailState } from "motionrail";
function TypedCarousel() {
let carousel:
| InstanceType<typeof import("motionrail").MotionRail>
| undefined;
const options: MotionRailOptions = {
autoplay: true,
breakpoints: [{ columns: 3, gap: "20px" }],
onChange: (state: MotionRailState) => {
console.log(state);
},
};
return (
<MotionRail ref={(instance) => (carousel = instance)} options={options}>
<div>Item 1</div>
<div>Item 2</div>
</MotionRail>
);
}Bundle Size
Solid.js integration: 0.89 kB (gzipped: 0.48 kB)
Next Steps
- Configuration - All configuration options
- API Methods - Programmatic control
- Extensions - Add more functionality